示例#1
0
def list_matching_torsions(smi_file, forcefield):
    from fragmenter import chemi  # chemi.file_to_oemols

    # generate oemols from smi file
    oemols = chemi.file_to_oemols(smi_file)
    # list of torsion parameters
    ff_torsion_param_list = forcefield.get_parameter_handler(
        'ProperTorsions').parameters

    # tid_molecules_list[tid] = [{'mol_index': mol_index, 'indices': indices, 'covered_tids':covered_tids}, ...]
    tid_molecules_list = {}
    failed_smi = []
    for torsion_param in ff_torsion_param_list:
        tid_molecules_list[torsion_param.id] = []

    for oemol in tqdm(oemols):
        try:
            off_mol, mol_index, center_bond = gen_canonical_isomeric_smiles(
                oemol)
            oemol = Molecule.to_openeye(off_mol)
        except:
            failed_smi.append(oechem.OEMolToSmiles(oemol))
            continue

        torsions_coverage = defaultdict(list)
        off_top = Topology.from_molecules(off_mol)
        center_tids = defaultdict(set)
        dihedrals = []
        for torsion_indices, torsion_param in forcefield.label_molecules(
                off_top)[0]['ProperTorsions'].items():
            i, j, k, l = torsion_indices
            if set([j, k]) == center_bond:
                center_tids[tuple(sorted([j, k]))].add(torsion_param.id)
                torsions_coverage[torsion_param].append(torsion_indices)
                dihedrals.append(torsion_indices)
        if not check_connectivity(dihedrals, oemol):
            print(f'## {mol_index} has diff bond info in oemol and offmol...')
            continue
        filtered_torsions_coverage = filter_torsions_coverage(
            torsions_coverage, oemol)  # check connectivity

        for idx, (tid, indices_list) in enumerate(
                filtered_torsions_coverage.items()):
            for idxx, indices in enumerate(indices_list):
                if idxx == 0:  # count once
                    covered_tids = []
                    i, j, k, l = indices
                    tids = center_tids[tuple(sorted([j, k]))]
                    for i in tids:
                        if i not in covered_tids:
                            covered_tids.append(i)
                    tid_molecules_list[tid].append({
                        'mol_index': mol_index,
                        'indices': indices,
                        'covered_tids': covered_tids
                    })
    print("\n## Torsion parameter: matched molecules ##\n" + '-' * 90)
    print(
        f"{'idx':<7} {'ID':7s} {'SMIRKS Pattern':70s} {'Number of molecules matched'}"
    )
    for idx, (tid, molecules_list) in enumerate(tid_molecules_list.items()):
        torsion_param = get_torsion_definition(ff_torsion_param_list, tid)
        print(
            f'{idx:<7} {torsion_param.id:7s} {torsion_param.smirks:70s} {len(molecules_list)}'
        )
    print('-' * 90)

    return tid_molecules_list, failed_smi
def gen_pdf(
    tid_clusters_list: list,
    output_path: str,
    cols: int = 8,
    cell_width: int = 200,
    cell_height: int = 200,
):
    from openeye import oechem, oedepict
    from openforcefield.topology import Molecule
    itf = oechem.OEInterface()
    PageByPage = True
    suppress_h = True

    n = sum([len(clusters) for tid, clusters in tid_clusters_list.items()])
    rows = math.ceil(n / cols)

    image = oedepict.OEImage(cell_width * cols, cell_height * rows)
    grid = oedepict.OEImageGrid(image, rows, cols)

    opts = oedepict.OE2DMolDisplayOptions(grid.GetCellWidth(),
                                          grid.GetCellHeight(),
                                          oedepict.OEScale_AutoScale)
    opts.SetAromaticStyle(oedepict.OEAromaticStyle_Circle)
    opts.SetTitleLocation(oedepict.OETitleLocation_Bottom)

    count = 0

    for tid, clusters in tid_clusters_list.items():
        for cluster in clusters:
            torsions = cluster['torsions']
            label = cluster['cluster_label']
            torsions = cluster['torsions']
            for torsion in torsions:
                cell = grid.GetCell(count // cols + 1, count % cols + 1)
                smi = torsion['mol_index']
                atom_indices = torsion['indices']
                # mol = oechem.OEGraphMol()
                # oechem.OESmilesToMol(mol, smi)

                off_mol = Molecule.from_smiles(smi,
                                               allow_undefined_stereo=True)
                off_mol = off_mol.canonical_order_atoms()
                mol = Molecule.to_openeye(off_mol)

                title = '{} ({})'.format(tid, set(torsion['covered_tids']))
                mol.SetTitle(title)

                oedepict.OEPrepareDepiction(mol, False, suppress_h)
                disp = oedepict.OE2DMolDisplay(mol, opts)

                # Highlight element of interest
                class NoAtom(oechem.OEUnaryAtomPred):
                    def __call__(self, atom):
                        return False

                class AtomInTorsion(oechem.OEUnaryAtomPred):
                    def __call__(self, atom):
                        return atom.GetIdx() in atom_indices

                class NoBond(oechem.OEUnaryBondPred):
                    def __call__(self, bond):
                        return False

                class CentralBondInTorsion(oechem.OEUnaryBondPred):
                    def __call__(self, bond):
                        return (bond.GetBgn().GetIdx() in atom_indices[1:3]
                                ) and (bond.GetEnd().GetIdx()
                                       in atom_indices[1:3])

                atoms = mol.GetAtoms(AtomInTorsion())
                bonds = mol.GetBonds(NoBond())
                abset = oechem.OEAtomBondSet(atoms, bonds)
                oedepict.OEAddHighlighting(
                    disp, oechem.OEColor(oechem.OEYellow),
                    oedepict.OEHighlightStyle_BallAndStick, abset)

                atoms = mol.GetAtoms(NoAtom())
                bonds = mol.GetBonds(CentralBondInTorsion())
                abset = oechem.OEAtomBondSet(atoms, bonds)
                oedepict.OEAddHighlighting(
                    disp, oechem.OEColor(oechem.OEMandarin),
                    oedepict.OEHighlightStyle_BallAndStick, abset)

                oedepict.OERenderMolecule(cell, disp)
                count += 1
    oedepict.OEWriteImage(output_path, image)
示例#3
0
    def fragment(self, molecule: Molecule) -> List[FragmentData]:
        """
        Fragment the molecule using the WBOFragmenter.

        Parameters:
            molecule: The openff molecule to be fragmented using the provided class settings

        Returns:
            A list of FragmentData schema which details how a parent molecule is related to a fragment and which bond
            we fragmented around.

        Raises:
            FragmenterError: If the molecule can not be fragmented.
        """
        from fragmenter import fragment

        # make sure the molecule has at least one conformer as this can cause issues
        if molecule.n_conformers == 0:
            molecule.generate_conformers(n_conformers=1)

        # set up the fragmenter
        fragment_factory = fragment.WBOFragmenter(
            molecule=molecule.to_openeye(), verbose=False)

        fragments: List[FragmentData] = []
        try:
            # fragment the molecule
            fragment_factory.fragment(
                threshold=self.wbo_threshold,
                keep_non_rotor_ring_substituents=self.
                keep_non_rotor_ring_substituents,
            )
            # now we work out the relation between the fragment and the parent
            fragments_data = fragment_factory.to_torsiondrive_json()
            # now store the data
            for data in fragments_data.values():
                off_frag = Molecule.from_mapped_smiles(
                    data["identifiers"]
                    ["canonical_isomeric_explicit_hydrogen_mapped_smiles"])
                # get the fragment parent mapping
                frag_dihedral = data["dihedral"][0][1:3]

                # in some cases we get one fragment back which is the parent molecule
                # we should not work out a mapping
                if not molecule.is_isomorphic_with(off_frag):
                    mapping = self._get_fragment_parent_mapping(
                        fragment=off_frag, parent=molecule)
                    # get the parent torsion
                    parent_dihedral = tuple(
                        [mapping[i] for i in frag_dihedral])
                    parent_molecule = molecule
                else:
                    # reuse the current fragment data as dummy parent data
                    mapping = dict((i, i) for i in range(molecule.n_atoms))
                    parent_dihedral = frag_dihedral
                    parent_molecule = off_frag
                # this is the data we need so make the fragmnetdata
                frag_data = FragmentData(
                    parent_molecule=parent_molecule,
                    parent_torsion=parent_dihedral,
                    fragment_molecule=off_frag,
                    fragment_torsion=frag_dihedral,
                    fragment_attributes=data["identifiers"],
                    fragment_parent_mapping=mapping,
                )
                fragments.append(frag_data)

            return fragments

        except RuntimeError:
            raise FragmenterError(
                f"The molecule {molecule} could not be fragmented so no fitting target was made."
            )