Ejemplo n.º 1
0
    def generate_fitting_task(
        self,
        molecule: off.Molecule,
        fragment: bool,
        attributes: MoleculeAttributes,
        fragment_parent_mapping: Optional[Dict[int, int]] = None,
        dihedrals: Optional[List[Tuple[int, int, int, int]]] = None,
    ) -> Union[TorsionTask, OptimizationTask, HessianTask]:
        """
        For the given collection workflow generate a task schema for the input molecule.
        """
        if molecule.n_conformers < self.target_conformers:
            molecule.generate_conformers(n_conformers=self.target_conformers,
                                         clear_existing=False)

        # build a dict of the data
        data = dict(
            name=self.collection_workflow,
            attributes=attributes,
            provenance=self.provenance(),
            fragment=fragment,
            fragment_parent_mapping=fragment_parent_mapping,
            molecule=molecule,
            dihedrals=dihedrals,
        )
        if self.collection_workflow == "torsion1d":
            task = TorsionTask(**data)
        elif self.collection_workflow == "optimization":
            task = OptimizationTask(**data)
        elif self.collection_workflow == "hessian":
            task = HessianTask(**data)
        else:
            raise NotImplementedError(
                f"The collection workflow {self.collection_workflow} is not supported."
            )
        return task
Ejemplo n.º 2
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."
            )