def atom_bond_set_to_mol(frag, oemol, adjust_hcount=False, RGroup=True):
    from openeye import oechem
    import warnings
    fragatompred = oechem.OEIsAtomMember(frag.GetAtoms())
    fragbondpred = oechem.OEIsBondMember(frag.GetBonds())

    fragment_oemol = oechem.OEMol()
    adjustHCount = adjust_hcount
    oechem.OESubsetMol(fragment_oemol, oemol, fragatompred, fragbondpred,
                       adjustHCount, RGroup)

    oechem.OEAddExplicitHydrogens(fragment_oemol)
    # sanity check that all atoms are bonded
    for atom in fragment_oemol.GetAtoms():
        if not list(atom.GetBonds()):
            warnings.warn(
                "Yikes!!! An atom that is not bonded to any other atom in the fragment. "
                "You probably ran into a bug. Please report the input molecule to the issue tracker"
            )
    # Perceive stereo and check that defined stereo did not change
    oechem.OEPerceiveChiral(fragment_oemol)
    oechem.OE3DToAtomStereo(fragment_oemol)
    oechem.OE3DToBondStereo(fragment_oemol)

    return fragment_oemol
예제 #2
0
파일: utils.py 프로젝트: sailfish009/gimlet
def file_to_oemols(filename):
    """Create OEMol from file. If more than one mol in file, return list of OEMols.

    Parameters
    ----------
    filename: str
        absolute path to oeb file

    Returns
    -------
    mollist: list
        list of OEMol for multiple molecules. OEMol if file only has one molecule.
    """
    from openeye import oechem

    if not os.path.exists(filename):
        raise Exception("File {} not found".format(filename))

    ifs = oechem.oemolistream(filename)
    mollist = []

    molecule = oechem.OEMol()
    while oechem.OEReadMolecule(ifs, molecule):
        molecule_copy = oechem.OEMol(molecule)
        oechem.OEPerceiveChiral(molecule_copy)
        oechem.OE3DToAtomStereo(molecule_copy)
        oechem.OE3DToBondStereo(molecule_copy)
        mollist.append(molecule_copy)
    ifs.close()

    if len(mollist) is 1:
        mollist = mollist[0]
    return mollist
예제 #3
0
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False):
    """
    Generate OEMol from QCSchema molecule specs
    Parameters
    ----------
    inp_molecule: dict
        Must have symbols and connectivity and/or geometry
        Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This
        will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and
        isomeric SMILES.

    Returns
    -------
    molecule: OEMol

    """

    molecule = oechem.OEMol()
    for s in symbols:
        molecule.NewAtom(_symbols[s])

    # Add connectivity
    for bond in connectivity:
        a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0]))
        a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1]))
        bond_order = bond[-1]
        if not isinstance(bond_order, int) and not bond_order.is_integer():
            raise ValueError(
                "bond order must be a whole number. A bond order of 1.5 is not allowed"
            )
        molecule.NewBond(a1, a2, int(bond_order))

    # Add geometry
    if molecule.NumAtoms() != geometry.shape[0] / 3:
        raise ValueError(
            "Number of atoms in molecule does not match length of position array"
        )

    molecule.SetCoords(oechem.OEFloatArray(geometry))
    molecule.SetDimension(3)

    if not permute_xyz:
        # Add tag that the geometry is from JSON and shouldn't be changed.
        geom_tag = oechem.OEGetTag("json_geometry")
        molecule.SetData(geom_tag, True)
    oechem.OEDetermineConnectivity(molecule)
    oechem.OEFindRingAtomsAndBonds(molecule)
    # No need to perceive Bond Order because the information was added from the connectivity table. Apparently, this
    # function does many different perceptions under the hood and it can add implicit hydrogens to divalent N that should be negatively charged.
    #oechem.OEPerceiveBondOrders(molecule)
    # This seems to add hydrogens that are not in the json
    #oechem.OEAssignImplicitHydrogens(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule)
    oechem.OEPerceiveChiral(molecule)
    oechem.OE3DToAtomStereo(molecule)
    oechem.OE3DToBondStereo(molecule)

    return molecule
예제 #4
0
def canonical_order_molecule_inplace(mol_list):
    """rearrange atoms in molecules to canonical ordering
    based on example from Chaya """
    if not mol_list: return
    toolkit = cmiles.utils._set_toolkit(mol_list[0])
    for oe_mol in mol_list:
        toolkit.canonical_order_atoms(oe_mol)
        # make sure stereochemistry is defined
        if not cmiles.utils.has_stereo_defined(oe_mol):
            oechem.OEPerceiveChiral(oe_mol)
            oechem.OE3DToAtomStereo(oe_mol)
            oechem.OE3DToBondStereo(oe_mol)
예제 #5
0
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False):
    """
    Generate OEMol from QCSchema molecule specs
    Parameters
    ----------
    inp_molecule: dict
        Must have symbols and connectivity and/or geometry
        Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This
        will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and
        isomeric SMILES.

    Returns
    -------
    molecule: OEMol

    """

    molecule = oechem.OEMol()
    for s in symbols:
        molecule.NewAtom(_symbols[s])

    # Add connectivity
    for bond in connectivity:
        a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0]))
        a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1]))
        molecule.NewBond(a1, a2, bond[-1])

    # Add geometry
    if molecule.NumAtoms() != geometry.shape[0] / 3:
        raise ValueError(
            "Number of atoms in molecule does not match length of position array"
        )

    molecule.SetCoords(oechem.OEFloatArray(geometry))
    molecule.SetDimension(3)

    if not permute_xyz:
        # Add tag that the geometry is from JSON and shouldn't be changed.
        geom_tag = oechem.OEGetTag("json_geometry")
        molecule.SetData(geom_tag, True)
    oechem.OEDetermineConnectivity(molecule)
    oechem.OEFindRingAtomsAndBonds(molecule)
    oechem.OEPerceiveBondOrders(molecule)
    # This seems to add hydrogens that are not in the json
    #oechem.OEAssignImplicitHydrogens(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule)
    oechem.OEPerceiveChiral(molecule)
    oechem.OE3DToAtomStereo(molecule)
    oechem.OE3DToBondStereo(molecule)

    return molecule
예제 #6
0
def PrepareDepiction(mol, clearcoords=False, suppressH=True):

    oechem.OESetDimensionFromCoords(mol)
    oechem.OEPerceiveChiral(mol)

    if mol.GetDimension() != 2 or clearcoords:
        if mol.GetDimension() == 3:
            oechem.OE3DToBondStereo(mol)
            oechem.OE3DToAtomStereo(mol)
        if suppressH:
            oechem.OESuppressHydrogens(mol)
        oechem.OEAddDepictionHydrogens(mol)

        oechem.OEDepictCoordinates(mol)
        oechem.OEMDLPerceiveBondStereo(mol)

    mol.SetDimension(2)
    return True
def main(infile):

    # open multi-molecule, multi-conformer file
    ifs = oechem.oemolistream()
    ifs.SetConfTest(oechem.OEAbsCanonicalConfTest())
    if not ifs.open(infile):
        raise FileNotFoundError(f"Unable to open {infile} for reading")
    mols = ifs.GetOEMols()

    for i, mol in enumerate(mols):

        # perceive stereochemistry for mol
        oechem.OEPerceiveChiral(mol)
        oechem.OEAssignAromaticFlags(mol, oechem.OEAroModel_MDL)

        # assign charges to copy of mol
        # note that chg_mol does NOT have conformers
        try:
            chg_mol = charge_mol(mol)

        except RuntimeError:

            # perceive stereochem
            #find_unspecified_stereochem(mol)
            oechem.OE3DToInternalStereo(mol)

            # reset perceived and call OE3DToBondStereo, since it may be missed
            # by OE3DToInternalStereo if it thinks mol is flat
            mol.ResetPerceived()
            oechem.OE3DToBondStereo(mol)

            try:
                chg_mol = charge_mol(mol)
                print(f'fixed stereo: {mol.GetTitle()}')
            except RuntimeError:
                find_unspecified_stereochem(mol)

                title = mol.GetTitle()
                smilabel = oechem.OEGetSDData(mol, "SMILES QCArchive")
                print(' >>> Charge assignment failed due to unspecified '
                      f'stereochemistry {title} {smilabel}')

                continue
예제 #8
0
def main(infile, outfile, ffxml, minimizer):

    # open multi-molecule, multi-conformer file
    ifs = oechem.oemolistream()
    ifs.SetConfTest(oechem.OEAbsCanonicalConfTest())
    if not ifs.open(infile):
        raise FileNotFoundError(f"Unable to open {infile} for reading")
    mols = ifs.GetOEMols()

    # open an outstream file
    ofs = oechem.oemolostream()
    if os.path.exists(outfile):
        raise FileExistsError("Output file {} already exists in {}".format(
            outfile, os.getcwd()))
    if not ofs.open(outfile):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % outfile)

    # minimize with openforcefield ffxml file
    for i, mol in enumerate(mols):

        # perceive stereochemistry for mol
        oechem.OEPerceiveChiral(mol)
        oechem.OEAssignAromaticFlags(mol, oechem.OEAroModel_MDL)

        # assign charges to copy of mol
        # note that chg_mol does NOT have conformers
        try:
            chg_mol = charge_mol(mol)

        except RuntimeError:
            # perceive stereochem
            #find_unspecified_stereochem(mol)
            oechem.OE3DToInternalStereo(mol)

            # reset perceived and call OE3DToBondStereo, since it may be missed
            # by OE3DToInternalStereo if it thinks mol is flat
            mol.ResetPerceived()
            oechem.OE3DToBondStereo(mol)

            try:
                chg_mol = charge_mol(mol)
                print(f'fixed stereo: {mol.GetTitle()}')
            except RuntimeError:
                title = mol.GetTitle()
                smilabel = oechem.OEGetSDData(mol, "SMILES QCArchive")
                print(' >>> Charge assignment failed due to unspecified '
                      f'stereochemistry {title} {smilabel}')
                continue

        for j, conf in enumerate(mol.GetConfs()):

            # perceive sterochemistry for conf coordinates
            oechem.OE3DToInternalStereo(conf)

            # assign charges to the conf itself
            chg_conf = charge_conf(chg_mol, conf)

            if minimizer == 'ffxml':
                # minimize with parsley (charges set by ff not used from conf)
                min_ffxml(chg_conf, ofs, ffxml)

            if minimizer == 'mmff94':
                # minimize with mmff94
                min_mmff94x(chg_conf, ofs, mmff94s=False)

            if minimizer == 'mmff94s':
                # minimize with mmff94S
                min_mmff94x(chg_conf, ofs, mmff94s=True)

            if minimizer == 'gaff':
                # minimize with gaff
                min_gaffx(chg_conf, ofs, gaff2=False)

            if minimizer == 'gaff2':
                # minimize with gaff2
                min_gaffx(chg_conf, ofs, gaff2=True)

    ifs.close()
    ofs.close()
예제 #9
0
def has_stereo_defined(molecule):
    """
    Check if any stereochemistry in undefined.
    Parameters
    ----------
    molecule: OEMol

    Returns
    -------
    bool: True if all stereo chemistry is defined.
        If any stereochemsitry is undefined, raise and exception.

    """

    # perceive stereochemistry
    oechem.OEPerceiveChiral(molecule)
    oechem.OE3DToAtomStereo(molecule)
    oechem.OE3DToBondStereo(molecule)

    unspec_chiral = False
    unspec_db = False
    problematic_atoms = list()
    problematic_bonds = list()
    for atom in molecule.GetAtoms():
        if atom.IsChiral() and not atom.HasStereoSpecified(
                oechem.OEAtomStereo_Tetrahedral):
            # Check if handness is specified
            v = []
            for nbr in atom.GetAtoms():
                v.append(nbr)
            stereo = atom.GetStereo(v, oechem.OEAtomStereo_Tetrahedral)
            if stereo == oechem.OEAtomStereo_Undefined:
                unspec_chiral = True
                problematic_atoms.append(
                    (atom.GetIdx(),
                     oechem.OEGetAtomicSymbol(atom.GetAtomicNum())))
    for bond in molecule.GetBonds():
        if bond.IsChiral() and not bond.HasStereoSpecified(
                oechem.OEBondStereo_CisTrans):
            v = []
            for neigh in bond.GetBgn().GetAtoms():
                if neigh != bond.GetEnd():
                    v.append(neigh)
                    break
            for neigh in bond.GetEnd().GetAtoms():
                if neigh != bond.GetBgn():
                    v.append(neigh)
                    break
            stereo = bond.GetStereo(v, oechem.OEBondStereo_CisTrans)

            if stereo == oechem.OEBondStereo_Undefined:
                unspec_db = True
                a1 = bond.GetBgn()
                a2 = bond.GetEnd()
                a1_idx = a1.GetIdx()
                a2_idx = a2.GetIdx()
                a1_s = oechem.OEGetAtomicSymbol(a1.GetAtomicNum())
                a2_s = oechem.OEGetAtomicSymbol(a2.GetAtomicNum())
                bond_order = bond.GetOrder()
                problematic_bonds.append(
                    (a1_idx, a1_s, a2_idx, a2_s, bond_order))
    if unspec_chiral or unspec_db:
        warnings.warn(
            "Stereochemistry is unspecified. Problematic atoms {}, problematic bonds {}, SMILES: {}"
            .format(problematic_atoms, problematic_bonds,
                    oechem.OEMolToSmiles(molecule)))
        return False
    else:
        return True
예제 #10
0
def _extract_oe_fragment(
    molecule: Molecule, atom_indices: Set[int], bond_indices: Set[Tuple[int, int]]
) -> Molecule:

    from openeye import oechem

    oe_molecule = molecule.to_openeye()

    # Restore the map indices as to_openeye does not automatically add them.
    for atom_index, map_index in molecule.properties["atom_map"].items():

        oe_atom = oe_molecule.GetAtom(oechem.OEHasAtomIdx(atom_index))
        oe_atom.SetMapIdx(map_index)

    # Include any Hs bonded to the included atom set so we can retain their map
    # indices.
    for map_index in {*atom_indices}:

        oe_atom = oe_molecule.GetAtom(oechem.OEHasMapIdx(map_index))

        for neighbour in oe_atom.GetAtoms():

            if (
                neighbour.GetAtomicNum() != 1
                or neighbour.GetMapIdx() < 1
                or neighbour.GetMapIdx() in atom_indices
            ):
                continue

            atom_indices.add(neighbour.GetMapIdx())
            bond_indices.add((map_index, neighbour.GetMapIdx()))

    atom_bond_set = oechem.OEAtomBondSet()

    for map_index in atom_indices:
        atom = oe_molecule.GetAtom(oechem.OEHasMapIdx(map_index))
        atom_bond_set.AddAtom(atom)

    for map_index_1, map_index_2 in bond_indices:

        atom_1 = oe_molecule.GetAtom(oechem.OEHasMapIdx(map_index_1))
        atom_2 = oe_molecule.GetAtom(oechem.OEHasMapIdx(map_index_2))

        bond = oe_molecule.GetBond(atom_1, atom_2)

        if not bond:
            raise ValueError(f"{(map_index_1, map_index_2)} is a disconnected bond")

        atom_bond_set.AddBond(bond)

    atom_predicate = oechem.OEIsAtomMember(atom_bond_set.GetAtoms())
    bond_predicate = oechem.OEIsBondMember(atom_bond_set.GetBonds())

    fragment = oechem.OEMol()
    oechem.OESubsetMol(fragment, oe_molecule, atom_predicate, bond_predicate, True)

    oechem.OEAddExplicitHydrogens(fragment)
    oechem.OEPerceiveChiral(fragment)

    # Always restore map?
    # if restore_maps:
    # In some cases (symmetric molecules) this changes the atom map so skip it
    # restore_atom_map(fragment)
    # atom map should be restored for combinatorial fragmentation
    # Perceive stereo and check that defined stereo did not change
    oechem.OEPerceiveChiral(fragment)
    oechem.OE3DToAtomStereo(fragment)
    oechem.OE3DToBondStereo(fragment)

    return Molecule.from_openeye(fragment, allow_undefined_stereo=True)