def _getFlippers(mol, options):
    Chem.FindPotentialStereoBonds(mol)

    flippers = []
    if not options.onlyStereoGroups:
        for atom in mol.GetAtoms():
            if atom.HasProp("_ChiralityPossible"):
                if (not options.onlyUnassigned or atom.GetChiralTag()
                        == Chem.ChiralType.CHI_UNSPECIFIED):
                    flippers.append(_AtomFlipper(atom))

        for bond in mol.GetBonds():
            bstereo = bond.GetStereo()
            if bstereo != Chem.BondStereo.STEREONONE:
                if (not options.onlyUnassigned
                        or bstereo == Chem.BondStereo.STEREOANY):
                    flippers.append(_BondFlipper(bond))

    if options.onlyUnassigned:
        # otherwise these will be counted twice
        for group in mol.GetStereoGroups():
            if group.GetGroupType() != Chem.StereoGroupType.STEREO_ABSOLUTE:
                flippers.append(_StereoGroupFlipper(group))

    return flippers
Example #2
0
def change_stereobond_in_imine_to_cis(mol: Chem.Mol) -> Chem.Mol:

    Chem.FindPotentialStereoBonds(mol)
    for bond in mol.GetBonds():
        if bond.GetStereo() == Chem.BondStereo.STEREOANY:
            logger.debug(
                f"{bond.GetBeginAtom().GetSymbol()} {bond.GetSmarts()} {bond.GetEndAtom().GetSymbol()}"
            )
            bond.SetStereo(Chem.BondStereo.STEREOZ)

    return mol
Example #3
0
def has_stereo_defined(molecule):
    #ToDo Fix this function for carbons with explicit hydrogen and imine with implicit hydrogens
    """

    Parameters
    ----------
    molecule

    Returns
    -------

    """
    unspec_chiral = False
    unspec_db = False
    problematic_atoms = list()
    problematic_bonds = list()
    # remove map indices and store. Then create molecule with SMILES without map indices and check for stereo on that.
    # This step is needed because even when map indices are stored in the data of the atoms, it is used for assigning potential
    # stereo centers. If a molecule does not have map indices but has data on the atoms, it will get flagged
    had_atom_map = False
    if has_atom_map(molecule):
        had_atom_map = True
        remove_atom_map(molecule)
    a = Chem.rdmolfiles.SmilesParserParams()
    a.removeHs = False
    mol_copy = Chem.MolFromSmiles(Chem.MolToSmiles(molecule), a)
    # restore map indices
    if had_atom_map:
        restore_atom_map(molecule)
    chiral_centers = Chem.FindMolChiralCenters(mol_copy,
                                               includeUnassigned=True)
    for center in chiral_centers:
        atom_id = center[0]
        if center[-1] == '?':
            unspec_chiral = True
            problematic_atoms.append(
                (atom_id, mol_copy.GetAtomWithIdx(atom_id).GetSmarts()))

    # Find potential stereo bonds that are unspecified
    Chem.FindPotentialStereoBonds(mol_copy)
    for bond in mol_copy.GetBonds():
        if bond.GetStereo() == Chem.BondStereo.STEREOANY:
            unspec_db = True
            problematic_bonds.append(
                (bond.GetBeginAtom().GetSmarts(), bond.GetSmarts(),
                 bond.GetEndAtom().GetSmarts()))
    if unspec_chiral or unspec_db:
        warnings.warn(
            "Stereochemistry is unspecified. Problematic atoms {}, problematic bonds {}"
            .format(problematic_atoms, problematic_bonds))
        return False
    else:
        return True
Example #4
0
def enumerate_stereoisomers(
    mol,
    n_variants: int = 20,
    undefined_only: bool = False,
    rationalise: bool = True,
):
    """Enumerate the stereocenters and bonds of the current molecule.

    Original source: the `openff-toolkit` lib.

    Warning: this function can be computationnaly intensive.

    Args:
        mol: The molecule whose state we should enumerate.
        n_variants: The maximum amount of molecules that should be returned.
        undefined_only: If we should enumerate all stereocenters and bonds or only those
            with undefined stereochemistry.
        rationalise: If we should try to build and rationalise the molecule to ensure it
            can exist.
    """
    from rdkit.Chem.EnumerateStereoisomers import EnumerateStereoisomers
    from rdkit.Chem.EnumerateStereoisomers import StereoEnumerationOptions

    # safety first
    mol = copy_mol(mol)

    # in case any bonds/centers are missing stereo chem flag it here
    Chem.AssignStereochemistry(mol, force=False, flagPossibleStereoCenters=True, cleanIt=True)  # type: ignore
    Chem.FindPotentialStereoBonds(mol, cleanIt=True)  # type: ignore

    # set up the options
    stereo_opts = StereoEnumerationOptions(
        tryEmbedding=rationalise,
        onlyUnassigned=undefined_only,
        maxIsomers=n_variants,
    )

    try:
        isomers = tuple(EnumerateStereoisomers(mol, options=stereo_opts))
    except:
        # NOTE(hadim): often got "Stereo atoms should be specified before specifying CIS/TRANS bond stereochemistry"
        # for the ligand of reference (coming from the PDB). Not sure how to handle that.
        isomers = []

    variants = []
    for isomer in isomers:
        # isomer has CIS/TRANS tags so convert back to E/Z
        Chem.SetDoubleBondNeighborDirections(isomer)  # type: ignore
        Chem.AssignStereochemistry(isomer, force=True, cleanIt=True)  # type: ignore
        variants.append(isomer)

    return variants
def _find_rd_stereocenters(
    molecule: Molecule,
) -> Tuple[List[int], List[Tuple[int, int]]]:
    """A method which returns the of the stereogenic atom and bonds of a molecule
    using the RDKit.

    Parameters
    ----------
    molecule
        The molecule whose stereocenters should be returned.

    Notes
    -----
    * This method currently deals with RDKit directly and should be removed once
      the API points suggested in openff-toolkit issue #903 have been added.

    Returns
    -------
        The indices of the stereogenic atoms in the molecule and the indices of the
        atoms involved in stereogenic bonds in the molecule.
    """

    from rdkit import Chem

    rd_molecule = molecule.to_rdkit()

    Chem.AssignStereochemistry(
        rd_molecule, cleanIt=True, force=True, flagPossibleStereoCenters=True
    )

    stereogenic_atoms = {
        atom.GetIdx()
        for atom in rd_molecule.GetAtoms()
        if atom.HasProp("_ChiralityPossible")
    }

    # Clear any previous assignments on the bonds, since FindPotentialStereo
    # may not overwrite it
    for bond in rd_molecule.GetBonds():
        bond.SetStereo(Chem.BondStereo.STEREONONE)

    Chem.FindPotentialStereoBonds(rd_molecule, cleanIt=True)

    stereogenic_bonds = {
        (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        for bond in rd_molecule.GetBonds()
        if bond.GetStereo() == Chem.BondStereo.STEREOANY
    }

    return sorted(stereogenic_atoms), sorted(stereogenic_bonds)
Example #6
0
def decide_unspec_stereo(smiles: str) -> str:
    m = Chem.MolFromSmiles(smiles)
    m = Chem.AddHs(m)

    Chem.FindPotentialStereoBonds(m)
    for bond in m.GetBonds():
        if bond.GetStereo() == Chem.BondStereo.STEREOANY:
            print(
                bond.GetBeginAtom().GetSymbol(),
                bond.GetSmarts(),
                bond.GetEndAtom().GetSymbol(),
            )
            bond.SetStereo(Chem.BondStereo.STEREOE)
    return Chem.MolToSmiles(m)
Example #7
0
def flag_unspec_stereo(smiles: str) -> bool:
    m = Chem.MolFromSmiles(smiles)
    m = Chem.AddHs(m)

    unspec = False
    Chem.FindPotentialStereoBonds(m)
    for bond in m.GetBonds():
        if bond.GetStereo() == Chem.BondStereo.STEREOANY:
            logger.debug(
                bond.GetBeginAtom().GetSymbol(),
                bond.GetSmarts(),
                bond.GetEndAtom().GetSymbol(),
            )
            unspec = True
    return unspec
def _getFlippers(mol, options):
    Chem.FindPotentialStereoBonds(mol)

    flippers = []
    for atom in mol.GetAtoms():
        if atom.HasProp("_ChiralityPossible"):
            if (not options.onlyUnassigned
                    or atom.GetChiralTag() == Chem.ChiralType.CHI_UNSPECIFIED):
                flippers.append(_AtomFlipper(atom))

    for bond in mol.GetBonds():
        bstereo = bond.GetStereo()
        if bstereo != Chem.BondStereo.STEREONONE:
            if (not options.onlyUnassigned
                    or bstereo == Chem.BondStereo.STEREOANY):
                flippers.append(_BondFlipper(bond))

    return flippers
Example #9
0
def has_stereo_defined(molecule):
    """

    Parameters
    ----------
    molecule

    Returns
    -------

    """

    unspec_chiral = False
    unspec_db = False
    problematic_atoms = list()
    problematic_bonds = list()
    chiral_centers = Chem.FindMolChiralCenters(molecule,
                                               includeUnassigned=True)
    for center in chiral_centers:
        atom_id = center[0]
        if center[-1] == '?':
            unspec_chiral = True
            problematic_atoms.append(
                (atom_id, molecule.GetAtomWithIdx(atom_id).GetSmarts()))

    # Find potential stereo bonds that are unspecified
    Chem.FindPotentialStereoBonds(molecule)
    for bond in molecule.GetBonds():
        if bond.GetStereo() == Chem.BondStereo.STEREOANY:
            unspec_db = True
            problematic_bonds.append(
                (bond.GetBeginAtom().GetSmarts(), bond.GetSmarts(),
                 bond.GetEndAtom().GetSmarts()))
    if unspec_chiral or unspec_db:
        warnings.warn(
            "Stereochemistry is unspecified. Problematic atoms {}, problematic bonds {}"
            .format(problematic_atoms, problematic_bonds))
        return False
    else:
        return True