def _GetSMILES(mol, idxlist): tmol = mol.__copy__() #(t)emporary tmol = RWMol(tmol) for AtomIdx in xrange(tmol.GetNumAtoms() - 1, -1, -1): if AtomIdx not in idxlist: tmol.RemoveAtom(AtomIdx) return Chem.MolToSmiles(tmol)
def to_rdkit_molecule(data): """ MoleculeContainer to RDKit molecule object converter """ mol = RWMol() conf = Conformer() mapping = {} is_3d = False for n, a in data.atoms(): ra = Atom(a.number) ra.SetAtomMapNum(n) if a.charge: ra.SetFormalCharge(a.charge) if a.isotope != a.common_isotope: ra.SetIsotope(a.isotope) if a.radical: ra.SetNumRadicalElectrons(a.radical) mapping[n] = m = mol.AddAtom(ra) conf.SetAtomPosition(m, (a.x, a.y, a.z)) if a.z: is_3d = True if not is_3d: conf.Set3D(False) for n, m, b in data.bonds(): mol.AddBond(mapping[n], mapping[m], _bond_map[b.order]) mol.AddConformer(conf) SanitizeMol(mol) return mol
def step(self, action_ob): """ Used to perform actions on the current molecule in the environment :param action_ob: The action to be taken on the current molecule :type action_ob: Action :return: Information about the resulting molecule :rtype: Observation """ action = action_ob.action_c.lower() position = action_ob.pos mol = action_ob.mol query = action_ob.query if (isinstance(action_ob.query, np.ndarray)): self._queryStep(action, query) else: self._simpleStep(action, position, mol) self.current_molecule = RWMol(Chem.MolFromSmiles(self._listToSmiles())) self.datacapture.processing() self.obs.update(self.current_molecule) self.mol_Steps.append(self.current_molecule) legend = str(len(self.mol_Steps)) + ". " + Chem.MolToSmiles( self.current_molecule) self.smiles.append(legend) if os.environ.get('DISPLAY', '') != '': img = Draw.MolToImage(self.current_molecule, size=(300, 300), kekulize=True, wedgeBonds=True) self.gui.update(img) return self.obs
def to_rdkit_molecule(data): """ MoleculeContainer to RDKit molecule object converter """ mol = RWMol() mapping = {} for n, a in data.atoms(): ra = Atom(a.atomic_number) ra.SetAtomMapNum(n) if a.charge: ra.SetFormalCharge(a.charge) if a.isotope: ra.SetIsotope(a.isotope) if a.is_radical: ra.SetNumRadicalElectrons(1) mapping[n] = mol.AddAtom(ra) for n, m, b in data.bonds(): mol.AddBond(mapping[n], mapping[m], _bond_map[b.order]) conf = Conformer() for n, a in data.atoms(): conf.SetAtomPosition(mapping[n], (a.x, a.y, 0)) conf.Set3D(False) mol.AddConformer(conf) for c in data._conformers: conf = Conformer() for n, xyz in c.items(): conf.SetAtomPosition(mapping[n], xyz) mol.AddConformer(conf) SanitizeMol(mol) return mol
def convert_dict_to_mols(tot_dict): """ :param tot_dict: :return: """ mol_list = [] for smiles in tot_dict: # Now generate the molecules for that mol = RWMol() atoms = tot_dict[smiles] print(atoms) for atom in atoms: atom = Atom(6) mol.AddAtom(atom) # for i in range(len(atoms)-1): # mol.AddBond(i,i+1) mol = mol.GetMol() AllChem.EmbedMolecule(mol) conf = mol.GetConformer() for i, atom in enumerate(atoms): point_3d = Point3D(atom[0], atom[1], atom[2]) conf.SetAtomPosition(i, point_3d) mol = conf.GetOwningMol() mol.SetProp("_Name", smiles) mol_list.append(mol) return mol_list
def decode(v): """Decode a molvector into a molecule :param v: molvector :result rdkit.RWMol: """ chunksize = atom_size + bond_chunk_size nchunks = len(v) // chunksize m = RWMol() bonds = {} for i in range(nchunks): start = i * (atom_size + bond_chunk_size) el, c, h, b1, o1, b2, o2, b3, o3, b4, o4 = v[start:start + chunksize] atom = Atom(el) atom.SetFormalCharge(c) atom.SetNumExplicitHs(h) atom_idx = m.AddAtom(atom) assert atom_idx == i for b, o in ((b1, o1), (b2, o2), (b3, o3), (b4, o4)): if o: to_atom = atom_idx + o bonds[tuple(sorted((atom_idx, to_atom)))] = b for (a1, a2), btype in bonds.items(): try: m.AddBond(a1 % m.GetNumAtoms(), a2 % m.GetNumAtoms(), BondType.values[btype]) except: pass return m
def remove_exocyclic_attachments(mol): """ Remove exocyclic and exolinker attachments from a molecule. Parameters ---------- mol : rdkit.Chem.rdchem.Mol Returns ------- rdkit.Chem.rdchem.Mol Molecule with exocyclic/exolinker attachments removed. """ edit = RWMol(mol) remove_atoms = set() for atom in edit.GetAtoms(): degree = atom.GetDegree() if degree == 1: bond = atom.GetBonds()[0] if bond.GetBondTypeAsDouble() == 2.0: nbr = bond.GetOtherAtom(atom) hcount = nbr.GetTotalNumHs() nbr.SetNumExplicitHs(hcount + 2) nbr.SetNoImplicit(True) remove_atoms.add(atom.GetIdx()) for aix in sorted(remove_atoms, reverse=True): edit.RemoveAtom(aix) rdmolops.AssignRadicals(edit) GetSymmSSSR(edit) return edit.GetMol()
def __init__(self): """ This is the constructor """ super().__init__() default_smile = 'C' self.current_molecule = RWMol(Chem.MolFromSmiles(default_smile)) self.obs = Observation(self.current_molecule) self.molecule_list = [Mol_Feature(default_smile)] self.datacapture = Datacapture(self.current_molecule) self.datacapture.processing() self.mol_Steps = [self.current_molecule] legend = str(len(self.mol_Steps)) + ". " + Chem.MolToSmiles( self.current_molecule) self.smiles = [legend] if os.environ.get('DISPLAY', '') != '': #check if there is a display available self.root = Toplevel() self.gui = Render(self.root) img = Draw.MolToImage(self.current_molecule, size=(300, 300), kekulize=True, wedgeBonds=True) self.gui.update(img) else: print('No display found!')
def depict(self, filename=None, ipython=False): from rdkit.Chem.Draw import IPythonConsole from rdkit.Chem.Draw import MolToImage from rdkit.Chem.Draw import rdMolDraw2D from rdkit.Chem.AllChem import EmbedMolecule from IPython.display import SVG from rdkit.Chem import RWMol, MolFromSmiles, Atom, BondType, ChiralType _ = MolFromSmiles('C') rmol = RWMol(_) dict_old_new_idx = {} n = 1 for a in self.atoms: old_idx = a.GetIdx() rmol.AddAtom(a) dict_old_new_idx[old_idx] = n n += 1 for a in self.enviroments: old_idx = a.GetIdx() a.SetChiralTag(ChiralType.CHI_UNSPECIFIED) a.SetIsAromatic(0) rmol.AddAtom(a) dict_old_new_idx[old_idx] = n n += 1 for b in self.Bonds: rmol.AddBond(dict_old_new_idx[b.GetBeginAtomIdx()], dict_old_new_idx[b.GetEndAtomIdx()], b.GetBondType()) for b in self.bondsenvironments: rmol.AddBond(dict_old_new_idx[b.GetBeginAtomIdx()], dict_old_new_idx[b.GetEndAtomIdx()], b.GetBondType()) rmol.RemoveAtom(0) EmbedMolecule(rmol) drawer = rdMolDraw2D.MolDraw2DSVG(400, 200) drawer.DrawMolecule(rmol) drawer.FinishDrawing() svg = drawer.GetDrawingText() if filename != None: f = open(filename, 'w') f.write(svg) f.close() if ipython: svg = svg.replace('svg:', '') return SVG(svg) else: return None
def get_ring_removals(smi): rw_mol = RWMol(Chem.MolFromSmiles(smi)) rings = rw_mol.GetRingInfo().AtomRings() out_mols = {} for ring in rings: new_mol = Chem.MolFromSmiles(smi) for atom in ring: new_mol.GetAtomWithIdx(atom).SetAtomicNum(0) Chem.DeleteSubstructs(new_mol, Chem.MolFromSmarts("[#0]")) Chem.GetMolFrags(new_mol) out_mols[Chem.MolToSmiles(new_mol, isomericSmiles=True)] = ring return out_mols
def to_rdkit_molecule(data: MoleculeContainer): """ MoleculeContainer to RDKit molecule object converter """ mol = RWMol() mapping = {} bonds = data._bonds for n, a in data.atoms(): ra = Atom(a.atomic_number) ra.SetAtomMapNum(n) if a.charge: ra.SetFormalCharge(a.charge) if a.isotope: ra.SetIsotope(a.isotope) if a.is_radical: ra.SetNumRadicalElectrons(1) mapping[n] = mol.AddAtom(ra) for n, m, b in data.bonds(): mol.AddBond(mapping[n], mapping[m], _bond_map[b.order]) for n in data._atoms_stereo: ra = mol.GetAtomWithIdx(mapping[n]) env = bonds[n] s = data._translate_tetrahedron_sign(n, [x for x in mapping if x in env]) ra.SetChiralTag(_chiral_ccw if s else _chiral_cw) for nm, s in data._cis_trans_stereo.items(): n, m = nm if m in bonds[n]: # cumulenes unsupported nn, nm, *_ = data._stereo_cis_trans[nm] b = mol.GetBondBetweenAtoms(mapping[n], mapping[m]) b.SetStereoAtoms(mapping[nn], mapping[nm]) b.SetStereo(_cis if s else _trans) conf = Conformer() for n, a in data.atoms(): conf.SetAtomPosition(mapping[n], (a.x, a.y, 0)) conf.Set3D(False) mol.AddConformer(conf, assignId=True) for c in data._conformers: conf = Conformer() for n, xyz in c.items(): conf.SetAtomPosition(mapping[n], xyz) mol.AddConformer(conf, assignId=True) SanitizeMol(mol) AssignStereochemistry(mol, flagPossibleStereoCenters=True, force=True) return mol
def test_step(self): #test add-back smile = "CC" smile = Chem.CanonSmiles(smile) m = Chem.CanonSmiles(self.env._listToSmiles()) self.assertEqual(m, smile) mols = [] legends = [] mols.append(RWMol(Chem.MolFromSmiles("C"))) legends.append("1. C") mols.append(RWMol(Chem.MolFromSmiles("CC"))) legends.append("2. CC") #test add-front self.action.setAction("add", pos="front", mol="C1=CC=CC=C1") self.env.step(self.action) smile = "CCC1=CC=CC=C1" smile = Chem.CanonSmiles(smile) m = Chem.CanonSmiles(self.env._listToSmiles()) self.assertEqual(m, smile) mols.append(RWMol(Chem.MolFromSmiles("CCC1=CC=CC=C1"))) l = "3. " + self.env._listToSmiles() legends.append(l) #test remove-back self.action.setAction("remove", pos="back", mol="C") self.env.step(self.action) smile = "C1=CC=CC=C1C" smile = Chem.CanonSmiles(smile) m = Chem.CanonSmiles(self.env._listToSmiles()) self.assertEqual(m, smile) mols.append(RWMol(Chem.MolFromSmiles("CC1=CC=CC=C1"))) l = "3. " + self.env._listToSmiles() legends.append(l) #test remove-front self.action.setAction("remove", pos="front", mol="C1=CC=CC=C1") self.env.step(self.action) smile = "C" smile = Chem.CanonSmiles(smile) m = Chem.CanonSmiles(self.env._listToSmiles()) self.assertEqual(m, smile) mols.append(RWMol(Chem.MolFromSmiles("C"))) l = "3. " + self.env._listToSmiles() legends.append(l) #test current molecule mol = self.env.current_molecule self.action.setAction("add", pos="front", mol="CC") self.env.step(self.action) self.assertNotEqual(self.env.current_molecule, mol) mols.append(RWMol(Chem.MolFromSmiles("CCC"))) l = "3. " + self.env._listToSmiles() legends.append(l)
def rd_map_from_ob(mol): from rdkit.Chem import RWMol, Atom, BondType rm = RWMol() for i in range(mol.NumAtoms()): a = mol.GetAtomById(i) ra = Atom(a.GetAtomicNum()) rm.AddAtom(ra) for i in range(mol.NumBonds()): b = mol.GetBondById(i) b.GetBeginAtom().GetId() order = BondType.SINGLE if b.GetBO() == 2: order = BondType.DOUBLE if b.GetBO() == 3: order = BondType.TRIPLE rm.AddBond(b.GetBeginAtom().GetId(), b.GetEndAtom().GetId(),order)#b.GetBondOrder()) return rm
def complement_reaction(rxn_template): if rxn_template.GetNumProductTemplates() != 1: print("[ERROR] A reaction template has only one product template.") sys.exit(1) pro = rxn_template.GetProductTemplate(0) rw_pro = RWMol(pro) amaps_pro = {a.GetAtomMapNum() for a in pro.GetAtoms()} amaps_rcts = {a.GetAtomMapNum() for rct in rxn_template.GetReactants() for a in rct.GetAtoms()} amaps_not_in_rcts = amaps_pro.intersection(amaps_rcts) for amap in amaps_not_in_rcts: aidx = [a.GetIdx() for a in rw_pro.GetAtoms() if a.GetAtomMapNum() == amap][0] rw_pro.RemoveAtom(aidx) m = rw_pro.GetMol() if '.' in Chem.MolToSmarts(m): return if (m.GetNumAtoms() == 0) or (m.GetNumAtoms() == 1 and m.GetAtomWithIdx(0).GetSymbol() in {"*", None}): return rxn_template.AddReactantTemplate(m)
def seed(self, Smiles): """ Resets the environment to a specified molecule :param Smiles: Smiles string for the molecule :type Smiles: string """ self.current_molecule = RWMol(Chem.MolFromSmiles(Smiles)) self.molecule_list = [Mol_Feature(Smiles)] self.obs = Observation(self.current_molecule) self.mol_Steps = [self.current_molecule] legend = str(len(self.mol_Steps)) + ". " + Chem.MolToSmiles( self.current_molecule) self.smiles.append(legend) self.datacapture = Datacapture(self.current_molecule) self.datacapture.processing()
def fragment(self, scaffold): """Fragment a scaffold into its next set of Murcko fragments. Parameters ---------- scaffold : scaffoldgraph.core.Scaffold Child scaffold to be fragmented. Returns ------- list A list of parent scaffolds representing the next hierarchy. """ parents = [] rings = scaffold.ring_systems # ring system information info = scaffold.rings.info if rings.count == 1: return [] for rix, ring in enumerate(rings): edit = RWMol(scaffold.mol) remove_atoms = set() for index, atom in zip(ring.aix, ring.atoms): if info.NumAtomRings(index) == 1 or any( [not b.IsInRing() for b in atom.GetBonds()]): if atom.GetDegree() > 2: # Evoke linker collection collect_linker_atoms(edit.GetAtomWithIdx(index), remove_atoms) else: remove_atoms.add(index) else: remove_atoms.add(index) for aix in sorted(remove_atoms, reverse=True): edit.RemoveAtom(aix) for parent in get_scaffold_frags(edit): if parent.ring_systems.count == len(rings) - 1: parent.removed_ring_idx = rix parents.append(parent) return parents
def Write(self, degrees, edges, canonical=True): if set(degrees).issubset(self.allowed): # Define the molecule cp = RWMol() _ = [cp.AddAtom(Atom(self.d2atno[D])) for D in degrees] _ = [cp.AddBond(f, t, BondType.SINGLE) for f, t in edges] # Export as canonical SMILES or a random SMILES if canonical: out = MolToSmiles(cp, canonical=True) else: out = MolToSmiles(cp, canonical=False, doRandom=True) # Carry out replacements for src, dst in self.replacements: out = out.replace(src, dst) return out.upper() else: return None
def fragment(self, scaffold): """Fragment a scaffold into its next set of murcko fragments. This fragmenter will not dissect fused ring systems. Parameters ---------- scaffold (sg.core.Scaffold): scaffold to be fragmented. Returns ------- parents (list): a list of the next scaffold parents. """ parents = [] rings = scaffold.ring_systems # ring system information info = scaffold.rings.info if rings.count == 1: return [] for rix, ring in enumerate(rings): edit = RWMol(scaffold.mol) remove_atoms = set() for index, atom in zip(ring.aix, ring.atoms): if info.NumAtomRings(index) == 1: if atom.GetDegree() > 2: # Evoke linker collection collect_linker_atoms(edit.GetAtomWithIdx(index), remove_atoms) else: remove_atoms.add(index) else: remove_atoms.add(index) for aix in sorted(remove_atoms, reverse=True): edit.RemoveAtom(aix) for parent in get_scaffold_frags(edit): if parent.ring_systems.count == len(rings) - 1: parent.removed_ring_idx = rix parents.append(parent) return parents
def _minimize_rings(mol): """Private: Minimize rings in a scaffold. In this process, all remaining vertices/atoms of degree two are removed by performing an edge merging operation. The only exception being when both vertices neighbours are connected (i.e. we have a triangle), when edge merging would lead to the loss of a cycle. The result is a minimum cycle topological representation of the original molecule. This function is used in the computation of ring topology scaffolds (Oprea). If a ring contains a non-carbon atom, this atom is maintained. Neighbouring ring atoms which are of the same type are merged together into a single atom of the corresponding type. Parameters ---------- mol : rdkit.Chem.rdchem.Mol Returns ------- rdkit.Chem.rdchem.RWMol Minimum cycle topological graph. """ edit = RWMol(mol) remove_atoms = set() for atom in edit.GetAtoms(): if atom.GetDegree() == 2: n1, n2 = atom.GetNeighbors() n1_idx, n2_idx = n1.GetIdx(), n2.GetIdx() connected = edit.GetBondBetweenAtoms(n1_idx, n2_idx) if not connected and (n1.GetAtomicNum() == atom.GetAtomicNum() or n2.GetAtomicNum() == atom.GetAtomicNum()): a_idx = atom.GetIdx() edit.RemoveBond(n1_idx, a_idx) edit.RemoveBond(n2_idx, a_idx) edit.AddBond(n1_idx, n2_idx, BondType.SINGLE) remove_atoms.add(a_idx) for a_idx in sorted(remove_atoms, reverse=True): edit.RemoveAtom(a_idx) return edit
def toStringRep(v): """Generate a string representation of a molvector :param v: molvector """ p = GetPeriodicTable() chunksize = atom_size + bond_chunk_size nchunks = len(v) // chunksize m = RWMol() out = [] for i in range(nchunks): start = i * (atom_size + bond_chunk_size) el, c, h, b1, o1, b2, o2, b3, o3, b4, o4 = v[start:start + chunksize] el = ("%2s" % p.GetElementSymbol(el)).replace(" ", "_") out.append(el) assert c < 10 out.append(str(c)) assert h < 10 out.append(str(h)) for btype, o in ((b1, o1), (b2, o2), (b3, o3), (b4, o4)): out.append(bond_symbols[btype]) out.append("%04d" % o) return "".join(out)
def __init__(self, smiles): """ This is the constructor :param smiles: The smile string for the molecule :type smiles: string """ self.smiles = smiles self.mol = RWMol(Chem.MolFromSmiles(smiles)) #create a feature a numpy array self.feats = factory.GetFeaturesForMol(self.mol) self.feature_arr = np.array([y.GetType() for y in self.feats]) print(self.feature_arr) #create a morgen finger print array self.fp = AllChem.GetMorganFingerprintAsBitVect(self.mol, 2, nBits=1024) self.fp_arr = np.zeros((1, 0)) DataStructs.ConvertToNumpyArray(self.fp, self.fp_arr) np.nonzero(self.fp_arr)
def _collapse_linker_bonds(mol, retain_het=False): """Private. condense linkers into a single chain. Used when constructing collapsed linker Murcko scaffolds and ring topology scaffolds. Parameters ---------- mol : rdkit.Chem.rdchem.Mol retain_het : bool, optional If True retain heteroatoms in the linker. The default is False. Returns ------- rdkit.Chem.rdchem.RWMol Mol object with collapsed linkers. """ def collapse(edit): for atom in edit.GetAtoms(): if atom.IsInRing(): continue nbrs = atom.GetNeighbors() if len(nbrs) == 2 and ( retain_het is False or nbrs[0].GetAtomicNum() == atom.GetAtomicNum() or nbrs[1].GetAtomicNum() == atom.GetAtomicNum()): nix = map(lambda x: x.GetIdx(), nbrs) edit.AddBond(*nix, BondType.SINGLE) edit.RemoveAtom(atom.GetIdx()) return collapse(edit) return edit edit = RWMol(mol) edit = collapse(edit) return edit
def reset(self): """ Resets the environment to its default state """ default_smile = 'C' self.current_molecule = RWMol(Chem.MolFromSmiles(default_smile)) self.obs = Observation(self.current_molecule) self.molecule_list = [Mol_Feature(default_smile)] self.mol_Steps = [self.current_molecule] legend = str(len(self.mol_Steps)) + ". " + Chem.MolToSmiles( self.current_molecule) self.smiles.append(legend) self.datacapture = Datacapture(self.current_molecule) self.datacapture.processing() if os.environ.get('DISPLAY', '') != '': self.gui.reset() img = Draw.MolToImage(self.current_molecule, size=(300, 300), kekulize=True, wedgeBonds=True) self.gui.update(img)
def link_li(rebuilt_smi): mol = Chem.MolFromSmiles(rebuilt_smi) mol = RWMol(mol) bons = [x[0] for x in mol.GetSubstructMatches(Chem.MolFromSmarts("[Xe]"))] mol.AddBond(bons[0], bons[1]) return mol.GetMol()
def get_mol(mol_parser, mol_data): rd_mol = mol_parser(mol_data) return RWMol(AllChem.AddHs(rd_mol))
def _contract_rings(mol): """Private: Return a molecule with rings contracted. Create a new molecule, replacing each ring with one atom. Atoms are connected if the rings they represent are connected by a bond not in any ring. If rings share a common bond, the bond added is double. If rings share an common atom (i.e. spiro rings) the rings are connected with a single bond. Used for generating ring connectivity scaffolds. Parameters ---------- mol : rdkit.Chem.rdchem.Mol Scaffold template for ring contraction. Returns ------- rcs : rdkit.Chem.rdchem.Mol New molecule with contracted rings. Notes ----- Dummy atoms are used instead of carbon atoms, so that valence constraints are not violated. In ring connectivity scaffolds the valence of a vertex is occaisionaly > 4. See Also -------- get_ring_connectivity_scaffold """ # Use a Scaffold object for ring + ring system information. scf, rcs = Scaffold(mol), RWMol() # Add a dummy atom for each ring to the empty RWMol. for _ in range(scf.rings.count): rcs.AddAtom(Atom(0)) # Create bonds between atoms (ring vertices). weak_connections, visited = set(), set() for system in scf.ring_systems: bc = set(system.get_bond_connectivity()) ac = set(system.get_atom_connectivity()) visited.update(system.aix) # link strongly connected rings (DOUBLE) for connection in ac.intersection(bc): rcs.AddBond(*connection, BondType.DOUBLE) # link weakly connected rings (SINGLE) for connection in ac.difference(bc): rcs.AddBond(*connection, BondType.SINGLE) # link rings connected by a linker (SINGLE) for rix, ring in zip(system.rix, system): to_visit = ring.get_attachment_points() while to_visit: aix = to_visit.pop() for nbr in scf.atoms[aix].GetNeighbors(): idx = nbr.GetIdx() if idx in visited: continue elif nbr.IsInRing(): visited.add(idx) for nix in _get_rings_with_atom(scf, idx): c = tuple(sorted((nix, rix))) weak_connections.add(c) continue else: to_visit.add(idx) visited.add(idx) # Add remaining weak ring connections (SINGLE) for connection in weak_connections: rcs.AddBond(*connection, BondType.SINGLE) return rcs.GetMol()
def fragment(self, scaffold): """Fragment a scaffold into its next set of Murcko fragments. Parameters ---------- scaffold : scaffoldgraph.core.Scaffold Child scaffold to be fragmented. Returns ------- list A list of parent scaffolds representing the next hierarchy. """ parents = [] # container for parent scaffolds rings = scaffold.rings # ring information for rix, ring in enumerate(rings): # Loop through all rings and remove edit = RWMol(scaffold.mol) # Editable molecule # Collect all removable atoms in the molecule remove_atoms = set() for index, atom in zip(ring.aix, ring.atoms): if rings.info.NumAtomRings(index) == 1: if atom.GetDegree() > 2: # Evoke linker collection collect_linker_atoms(edit.GetAtomWithIdx(index), remove_atoms) else: # Add ring atom to removable set remove_atoms.add(index) else: # Atom is shared between multiple rings correct_atom_props(edit.GetAtomWithIdx(index)) # Collect removable bonds (this needs to be done to prevent the case where when deleting # a ring two atoms belonging to the same bond are also part of separate other rings. # This bond must be broken to prevent an incorrect output) remove_bonds = set() for bix in { x for x in ring.bix if rings.info.NumBondRings(x) == 1 }: bond = edit.GetBondWithIdx(bix) b_x, b_y = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx() if b_x not in remove_atoms and b_y not in remove_atoms: remove_bonds.add((b_x, b_y)) correct_atom_props(edit.GetAtomWithIdx(b_x)) correct_atom_props(edit.GetAtomWithIdx(b_y)) # Scheme 4 (scaffold tree rule) if self.use_scheme_4 is not False and len(ring) == 3: atomic_nums = [a.GetAtomicNum() for a in ring.atoms] if len([a for a in atomic_nums if a != 1 and a != 6]) == 1: shared = { x for x in ring.bix if rings.info.NumBondRings(x) > 1 } if len(shared) == 1: bond = edit.GetBondWithIdx(shared.pop()) bond.SetBondType(BondType.DOUBLE) # Remove collected atoms and bonds for bix in remove_bonds: edit.RemoveBond(*bix) for aix in sorted(remove_atoms, reverse=True): edit.RemoveAtom(aix) # Add new parent scaffolds to parent list for parent in get_scaffold_frags(edit): if parent.rings.count == len(rings) - 1: parent.removed_ring_idx = rix parents.append(parent) return parents
def setUp(self): self.mol = RWMol(Chem.MolFromSmiles("C")) self.obs = observation.Observation(self.mol)
def test_update(self): mol = RWMol(Chem.MolFromSmiles("CC")) self.obs.update(mol) self.assertEquals(self.obs.mol, mol)