Beispiel #1
0
def _compute_fragment_join(
    mol,
    fragment,
    mol_atom_count,
    bond_between_rings=True,
    asMols=True,
):
    """List all posibilities of where a fragment can be attached to a mol"""
    fragment = copy.copy(
        fragment
    )  # need to copy the fragment copy is faster than all the other methods
    with dm.without_rdkit_log():
        combined = Chem.CombineMols(mol, fragment)
        for i1 in range(mol.GetNumAtoms()):
            a1 = combined.GetAtomWithIdx(i1)
            if a1.GetImplicitValence() == 0:
                continue
            for i2 in range(fragment.GetNumAtoms()):
                i2 += mol_atom_count
                a2 = combined.GetAtomWithIdx(i2)
                if a2.GetImplicitValence() == 0:
                    continue
                # no bond between atoms already in rings
                if not bond_between_rings and a1.IsInRing() and a2.IsInRing():
                    continue
                # no bond to form large rings
                else:
                    possibilities = _all_atom_join(combined, a1, a2)
                    for x in possibilities:
                        x = dm.sanitize_mol(x)
                        if x is not None:
                            if not asMols:
                                x = dm.to_smiles(x)
                            yield x
Beispiel #2
0
def _all_atom_join(mol, a1, a2):
    """Join two atoms (a1, a2) in a molecule in all possible valid manner"""
    new_mols = []
    with dm.without_rdkit_log():
        try:
            Chem.Kekulize(mol, clearAromaticFlags=True)
        except:
            pass
        v1, v2 = a1.GetImplicitValence(), a2.GetImplicitValence()
        bond = mol.GetBondBetweenAtoms(a1.GetIdx(), a2.GetIdx())
        if bond is None:
            if v1 > 0 and v2 > 0:
                new_mols.append(add_bond_between(mol, a1, a2, dm.SINGLE_BOND))
            if v1 > 1 and v2 > 1:
                new_mols.append(add_bond_between(mol, a1, a2, dm.DOUBLE_BOND))
            if v1 > 2 and v2 > 2:
                new_mols.append(add_bond_between(mol, a1, a2, dm.TRIPLE_BOND))

        elif bond.GetBondType() == dm.SINGLE_BOND:
            if v1 > 0 and v2 > 0:
                new_mols.append(update_bond(mol, bond, dm.DOUBLE_BOND))
            if v1 > 1 and v2 > 1:
                new_mols.append(update_bond(mol, bond, dm.TRIPLE_BOND))

        elif bond.GetBondType() == dm.DOUBLE_BOND:
            if v1 > 0 and v2 > 0:
                new_mols.append(update_bond(mol, bond, dm.TRIPLE_BOND))
    return [mol for mol in new_mols if mol is not None]
Beispiel #3
0
def update_bond(mol, bond, bond_type):
    """Update bond type between atoms"""
    new_mol = dm.copy_mol(mol)
    with dm.without_rdkit_log():
        new_bond = new_mol.GetBondWithIdx(bond.GetIdx())
        new_bond.SetBondType(bond_type)
    return dm.sanitize_mol(new_mol)
Beispiel #4
0
def test_rdkit_log(capfd):
    """Test multiple rdkit log scenarios."""

    check_logs_are_shown(capfd)
    with dm.without_rdkit_log():
        check_logs_are_not_shown(capfd)
    check_logs_are_shown(capfd)

    dm.disable_rdkit_log()
    check_logs_are_not_shown(capfd)

    dm.enable_rdkit_log()
    check_logs_are_shown(capfd)

    dm.disable_rdkit_log()
    with dm.without_rdkit_log():
        check_logs_are_not_shown(capfd)
    check_logs_are_not_shown(capfd)
Beispiel #5
0
def all_atom_add(
        mol,
        atom_types=["C", "N", "O", "F", "Cl", "Br"],
        asMols=True,
        max_num_action=float("Inf"),
        **kwargs,
):
    """Add a new atom on the mol, by considering all bond type

    .. warning::
        This is computationally expensive

    Args:
        mol: <Chem.Mol>
            Input molecule
        atom_types: list
            List of atom symbol to use as replacement
            (Default: ["C", "N", "O", "F", "Cl", "Br"])
        asMols: bool, optional
            Whether to return output as molecule or smiles
        max_num_action: float, optional
            Maximum number of action to reduce complexity
    Returns:
        All possible molecules with one additional atom added

    """
    new_mols = []
    stop = False
    with dm.without_rdkit_log():
        for atom in mol.GetAtoms():
            if stop:
                break
            if atom.GetImplicitValence() == 0:
                continue
            for atom_symb in atom_types:
                emol = Chem.RWMol(mol)
                new_index = emol.AddAtom(Chem.Atom(atom_symb))
                emol.UpdatePropertyCache(strict=False)
                new_mols.extend(
                    _all_atom_join(emol, atom,
                                   emol.GetMol().GetAtomWithIdx(new_index)))
                if len(new_mols) > max_num_action:
                    stop = True
                    break

        new_mols = [dm.sanitize_mol(mol) for mol in new_mols]
        new_mols = [mol for mol in new_mols if mol is not None]
        if not asMols:
            return [dm.to_smiles(x) for x in new_mols if x]
    return new_mols
Beispiel #6
0
def all_transform_apply(
    mol,
    rxns,
    max_num_action=float("Inf"),
    asMols=True,
    **kwargs,
):
    """
    Apply a transformation defined as a reaction from a set of reaction to the input molecule.

    The reaction need to be one reactant-only

    Arguments
    ----------
        mol: <Chem.Mol>
            Input molecule
        rnxs: list
            list of reactions/ reaction smarts
        max_num_action: int, optional
            Maximum number of result to return
            (Default: inf)
        asMols: bool, optional
            Whether to return smiles or mols

    Returns
    -------
        Products obtained from applying the chemical reactions
    """

    mols = set([])
    with dm.without_rdkit_log():
        for rxn in rxns:
            if len(mols) >= max_num_action:
                break
            if isinstance(rxn, str):
                rxn = AllChem.ReactionFromSmarts(rxn)
            try:
                pcdts = [products[0] for products in rxn.RunReactants([mol])]
                pcdts = [dm.sanitize_mol(x) for x in pcdts]
                mols.update([dm.to_smiles(x) for x in pcdts if x])
            except:
                pass
    mols = [x for x in mols if x is not None]
    if np.isfinite(max_num_action):
        mols = mols[:max_num_action]

    mols = [dm.to_mol(x) for x in mols]
    if not asMols:
        mols = [dm.to_smiles(x) for x in mols if x is not None]
    return mols
Beispiel #7
0
def all_atom_replace(mol,
                     atom_types=["C", "N", "S", "O"],
                     asMols=True,
                     max_num_action=float("Inf"),
                     **kwargs):
    """Replace all non-hydrogen atoms by other possibilities.

    .. warning::
        This is computationally expensive

    Args:
        mol: <Chem.Mol>
            Input molecule
        atom_types: list
            List of atom symbol to use as replacement
            (Default: ['C', 'N', 'S', 'O'])
        asMols: bool, optional
            Whether to return output as molecule or smiles
        max_num_action: float, optional
            Maximum number of action to reduce complexity

    Returns:
        All possible molecules with atoms replaced

    """
    new_mols = []
    stop = False
    with dm.without_rdkit_log():
        for atom in mol.GetAtoms():
            if stop:
                break
            if atom.GetAtomicNum() > 1:
                for atom_symb in atom_types:
                    emol = Chem.RWMol(mol)
                    emol.ReplaceAtom(atom.GetIdx(), Chem.Atom(atom_symb))
                    new_mols.append(emol)
                    if len(new_mols) > max_num_action:
                        stop = True
                        break

        # Sanitize and remove bad molecules
        new_mols = [dm.sanitize_mol(mol) for mol in new_mols]
        new_mols = [mol for mol in new_mols if mol is not None]

    if not asMols:  # Return SMILES
        return [dm.to_smiles(x) for x in new_mols]
    return new_mols