Exemplo n.º 1
0
    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
Exemplo n.º 2
0
 def _prevent_bridge_ring(self, mol: Chem.RWMol, examplar: Tuple[int]):
     ## This is really
     # examplar is ring
     ringatoms = self._get_ring_info(mol) #GetRingInfo().AtomRings()
     ringatoms = [ring for ring in ringatoms if set(ring).intersection(examplar)]
     ring_idx = list(range(len(ringatoms)))
     shared_count = {}
     for ra, rb in itertools.combinations(ring_idx, r=2):
         shared_count[(ra, rb)] = len(set(ringatoms[ra]).intersection(set(ringatoms[rb])))
     if len(shared_count) == 0:
         return mol
     ra, rb = list(shared_count.keys())[0]
     shared = list(set(ringatoms[ra]).intersection(ringatoms[rb]))
     pairs = [(a, b) for a, b in itertools.combinations(shared, r=2) if mol.GetBondBetweenAtoms(a, b) is not None]
     c = Counter([i for pair in pairs for i in pair])
     ring_A, ring_B = ringatoms[ra], ringatoms[rb]
     small, big = sorted([ring_A, ring_B], key=lambda ring: len(ring))
     inners = [i for i in c if c[i] > 1]
     x = list(set(shared).difference(inners))
     if len(x) != 2:
         log.critical(f'This is impossible. {ringatoms} share {shared} with {inners} in the inside and {x} on the edge?')
         return mol
     a, b = x
     if len(big) > 6:
         log.warning(f'Removing {len(inners)} bridging atoms and replacing with fused ring')
         # bond the vertices
         bt = Chem.BondType.SINGLE # ???
         if mol.GetBondBetweenAtoms(a, b) is None:
             mol.AddBond(a, b, bt)
         else:
             log.warning('This is really odd! Why is there a bond already??')
         # remove the middle atoms.
         for i in sorted(inners, reverse=True):
             mol.RemoveAtom(i)
     else:
         log.warning(f'Shriking the smaller ring to change from bridged to fused.')
         # get the neighbour in the small atom to a vertex.
         neighs = [neigh for neigh in mol.GetAtomWithIdx(a).GetNeighbors() if
                   neigh.GetIdx() not in shared and neigh.GetIdx() in small]
         neigh = sorted(neighs, key=lambda atom: atom.GetSymbol() != 'C')[0]
         bt = mol.GetBondBetweenAtoms(a, neigh.GetIdx()).GetBondType()
         mol.RemoveBond(a, neigh.GetIdx())
         new_neigh = [neigh for neigh in mol.GetAtomWithIdx(a).GetNeighbors() if neigh.GetIdx() in shared][0]
         mol.AddBond(neigh.GetIdx(), new_neigh.GetIdx(), bt)
         neigh.SetBoolProp('_Novel', True)
         new_neigh.SetBoolProp('_Novel', True)
         mol.GetAtomWithIdx(a).SetBoolProp('_Novel', True)
     return mol
Exemplo n.º 3
0
 def _place_between(self, mol: Chem.RWMol, a: int, b: int, aromatic=True):
     oribond = mol.GetBondBetweenAtoms(a, b)
     if oribond is None:
         print('FAIL')
         return None  # fail
     elif aromatic:
         bt = Chem.BondType.AROMATIC
     else:
         bt = oribond.GetBondType()
     idx = mol.AddAtom(Chem.Atom(6))
     neoatom = mol.GetAtomWithIdx(idx)
     atom_a = mol.GetAtomWithIdx(a)
     atom_b = mol.GetAtomWithIdx(b)
     if aromatic:
         neoatom.SetIsAromatic(True)
         atom_a.SetIsAromatic(True)
         atom_b.SetIsAromatic(True)
     # prevent constraints
     neoatom.SetBoolProp('_Novel', True)
     atom_a.SetBoolProp('_Novel', True)
     atom_b.SetBoolProp('_Novel', True)
     # fix position
     conf = mol.GetConformer()
     pos_A = conf.GetAtomPosition(a)
     pos_B = conf.GetAtomPosition(b)
     x = pos_A.x / 2 + pos_B.x / 2
     y = pos_A.y / 2 + pos_B.y / 2
     z = pos_A.z / 2 + pos_B.z / 2
     conf.SetAtomPosition(idx, Point3D(x, y, z))
     # fix bonds
     mol.RemoveBond(a, b)
     mol.AddBond(a, idx, bt)
     mol.AddBond(b, idx, bt)
Exemplo n.º 4
0
    def apply(self, mol: RWMol) -> RWMol:
        num_atoms = mol.GetNumAtoms()
        if self.detach:
            for i, a in enumerate(mol.GetAtoms()):
                m = a.GetAtomMapNum()
                if m == self.atom_map2:
                    for bond in a.GetBonds():
                        mol.RemoveBond(bond.GetBeginAtomIdx(),
                                       bond.GetEndAtomIdx())
                    mol.RemoveAtom(i)
                    num_atoms -= 1
                    break

        atom_ind = get_atom_ind(mol, self.atom_map1)
        b_type = rdchem.BondType.values[self.bond_type]
        b_stereo = rdchem.BondStereo.values[self.bond_stereo]

        old_atom = mol.GetAtomWithIdx(atom_ind)
        if old_atom.HasProp('in_reactant'):
            self.new_a.SetBoolProp('in_reactant',
                                   old_atom.GetBoolProp('in_reactant'))
        if old_atom.HasProp('mol_id'):
            self.new_a.SetIntProp('mol_id', old_atom.GetIntProp('mol_id'))

        mol.AddAtom(self.new_a)
        new_atom_ind = num_atoms

        bond_ind = mol.AddBond(atom_ind, new_atom_ind, order=b_type) - 1
        new_bond = mol.GetBondWithIdx(bond_ind)
        new_bond.SetStereo(b_stereo)
        new_bond.SetBoolProp('is_edited', True)

        return mol
Exemplo n.º 5
0
    def apply(self, mol: RWMol) -> RWMol:
        atom1 = get_atom_ind(mol, self.atom_map1)
        atom2 = get_atom_ind(mol, self.atom_map2)

        if self.bond_type is None:  # delete bond
            bond = mol.GetBondBetweenAtoms(atom1, atom2)
            if bond is not None:
                mol.RemoveBond(atom1, atom2)
        else:
            b_type = rdchem.BondType.values[self.bond_type]
            b_stereo = rdchem.BondStereo.values[self.bond_stereo]

            bond = mol.GetBondBetweenAtoms(atom1, atom2)
            if bond is None:  # add new bond
                bond_ind = mol.AddBond(atom1, atom2, order=b_type) - 1
                bond = mol.GetBondWithIdx(bond_ind)
            else:  # change an existing bond
                bond.SetBondType(b_type)
            bond.SetStereo(b_stereo)
            bond.SetBoolProp('is_edited', True)

            if b_type == BondType.AROMATIC:
                bond.SetIsAromatic(True)
                mol.GetAtomWithIdx(atom1).SetIsAromatic(True)
                mol.GetAtomWithIdx(atom2).SetIsAromatic(True)

        return mol
Exemplo n.º 6
0
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
Exemplo n.º 7
0
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
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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
Exemplo n.º 10
0
 def _restore_original_bonding(self, mol: Chem.RWMol, rings) -> None:
     to_be_waited_for = []
     for ring in rings:
         for i in range(len(ring['elements'])):
             d = self._get_expansion_for_atom(ring, i)
             new_i = self._get_new_index(mol, d['ori_i'], search_collapsed=False)
             for old_neigh, bond in zip(d['neighbor'], d['bond']):
                 bt = getattr(Chem.BondType, bond)
                 try:
                     new_neigh = self._get_new_index(mol, old_neigh, search_collapsed=False)
                     present_bond = mol.GetBondBetweenAtoms(new_i, new_neigh)
                     if present_bond is None:
                         mol.AddBond(new_i, new_neigh, bt)
                     elif present_bond.GetBondType().name != bond:
                         if self._debug_draw:
                             print(
                                 f'bond between {new_i} {new_neigh} exists already (has {present_bond.GetBondType().name} expected {bt})')
                         present_bond.SetBondType(bt)
                     else:
                         if self._debug_draw:
                             print(f'bond between {new_i} {new_neigh} exists already ' + \
                                   f'(has {present_bond.GetBondType().name} expected {bt})')
                         pass
                 except ValueError:
                     if self._debug_draw:
                         print(f"The neighbour {old_neigh} of {d['ori_i']} with {bt} does not yet exist")
                     to_be_waited_for.append((new_i, old_neigh, bt))
     for new_i, old_neigh, bt in to_be_waited_for:
         try:
             new_neigh = self._get_new_index(mol, old_neigh, name_restriction=mol.GetAtomWithIdx(new_i).GetProp('_ori_name'))
             if self._debug_draw:
                 print(f'{old_neigh} was missing, but has appeared since as {new_neigh}')
             if not mol.GetBondBetweenAtoms(new_i, new_neigh):
                 mol.AddBond(new_i, new_neigh, bt)
         except (KeyError, ValueError) as err:
             warn(str(err))
Exemplo n.º 11
0
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
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
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
Exemplo n.º 14
0
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()
Exemplo n.º 15
0
    def _join_atoms(self,
                    combo: Chem.RWMol,
                    anchor_A: int,
                    anchor_B: int,
                    distance: float,
                    linking: bool = True):
        """
        extrapolate positions between. by adding linkers if needed.
        """
        conf = combo.GetConformer()
        pos_A = conf.GetAtomPosition(anchor_A)
        pos_B = conf.GetAtomPosition(anchor_B)
        n_new = int(round(distance / 1.22) - 1)
        xs = np.linspace(pos_A.x, pos_B.x, n_new + 2)[1:-1]
        ys = np.linspace(pos_A.y, pos_B.y, n_new + 2)[1:-1]
        zs = np.linspace(pos_A.z, pos_B.z, n_new + 2)[1:-1]

        # correcting for ring marker atoms
        def is_ring_atom(anchor: int) -> bool:
            atom = combo.GetAtomWithIdx(anchor)
            if atom.HasProp('_ori_i') and atom.GetIntProp('_ori_i') == -1:
                return True
            else:
                return False

        if is_ring_atom(anchor_A):
            distance -= 1.35 + 0.2  # Arbitrary + 0.2 to compensate for the ring not reaching (out of plane).
            n_new -= 1
            xs = xs[1:]
            ys = ys[1:]
            zs = zs[1:]

        if is_ring_atom(anchor_B):
            distance -= 1.35 + 0.2  # Arbitrary + 0.2 to compensate for the ring not reaching  (out of plane).
            n_new -= 1
            xs = xs[:-1]
            ys = ys[:-1]
            zs = zs[:-1]

        # notify that things could be leary.
        if distance < 0:
            self.journal.debug(
                f'Two ring atoms detected to be close. Joining for now.' +
                ' They will be bonded/fused/spiro afterwards')
        # check if valid.
        if distance > self.joining_cutoff:
            msg = f'Atoms {anchor_A}+{anchor_B} are {distance} Å away. Cutoff is {self.joining_cutoff}.'
            self.journal.warning(msg)
            raise ConnectionError(msg)
        # place new atoms
        self.journal.debug(
            f'Molecules will be joined via atoms {anchor_A}+{anchor_B} ({distance} Å) via the addition of {n_new} atoms.'
        )
        previous = anchor_A
        if linking is False and n_new > 0:
            self.journal.warning(
                f'Was going to bond {anchor_A} and {anchor_B} but reconsidered.'
            )
        elif linking is True and n_new <= 0:
            combo.AddBond(previous, anchor_B, Chem.BondType.SINGLE)
            new_bond = combo.GetBondBetweenAtoms(previous, anchor_B)
            BondProvenance.set_bond(new_bond, 'main_novel')
        elif linking is False and n_new <= 0:
            combo.AddBond(previous, anchor_B, Chem.BondType.SINGLE)
            new_bond = combo.GetBondBetweenAtoms(previous, anchor_B)
            BondProvenance.set_bond(new_bond, 'other_novel')
        elif linking is True and n_new > 0:
            for i in range(n_new):
                # make oxygen the first and last bridging atom.
                if i == 0 and combo.GetAtomWithIdx(
                        anchor_A).GetSymbol() == 'C':
                    new_atomic = 8
                elif i > 2 and i == n_new - 1 and combo.GetAtomWithIdx(
                        anchor_B).GetSymbol() == 'C':
                    new_atomic = 8
                else:
                    new_atomic = 6
                idx = combo.AddAtom(Chem.Atom(new_atomic))
                new = combo.GetAtomWithIdx(idx)
                new.SetBoolProp('_Novel', True)
                new.SetIntProp('_ori_i', 999)
                conf.SetAtomPosition(
                    idx, Point3D(float(xs[i]), float(ys[i]), float(zs[i])))
                combo.AddBond(idx, previous, Chem.BondType.SINGLE)
                new_bond = combo.GetBondBetweenAtoms(idx, previous)
                BondProvenance.set_bond(new_bond, 'linker')
                previous = idx
            combo.AddBond(previous, anchor_B, Chem.BondType.SINGLE)
            new_bond = combo.GetBondBetweenAtoms(previous, anchor_B)
            BondProvenance.set_bond(new_bond, 'linker')
        else:
            raise ValueError('Impossible')
        return combo.GetMol()