Example #1
0
    def _generate_conformations_from_mol(self,
                                         mol: Chem.Mol,
                                         nr_of_conformations: int,
                                         enforceChirality: bool = True):
        """
        Helper function - does not need to be called directly.
        Generates conformations from a rdkit mol object.
        """

        charge = 0
        for at in mol.GetAtoms():
            if at.GetFormalCharge() != 0:
                charge += int(at.GetFormalCharge())

        if charge != 0:
            print(Chem.MolToSmiles(mol))
            raise NotImplementedError("Charged system")

        mol.SetProp("smiles", Chem.MolToSmiles(mol))
        mol.SetProp("charge", str(charge))
        mol.SetProp("name", str(self.name))

        # generate numConfs for the smiles string
        new_confs = Chem.rdDistGeom.EmbedMultipleConfs(
            mol,
            numConfs=nr_of_conformations,
            enforceChirality=enforceChirality,
            ignoreSmoothingFailures=True,
        )  # NOTE enforceChirality!

        # AllChem.AlignMolConformers(mol)
        assert int(mol.GetNumConformers()) != 0
        assert int(mol.GetNumConformers()) == nr_of_conformations

        return mol
Example #2
0
    def extract_features(self, ligand: Chem.Mol,
                         conformer_index: int) -> List[PharmacophoricPoint]:
        """ Extract the pharmacophoric points from a ligand.
        
            Parameters
            ----------
            ligand : rdkit.Chem.Mol
                A ligand
            
            conformer_index : int
                The conformer whose coordinates will be used to obtain the pharmacophoric
                points.
            
            Returns
            -------
            pharmacophoric_points : list of openpharmacophore.PharmacophoricPoint
                List of pharmacophoric points.
                
        """
        if ligand.GetNumConformers() == 0:
            raise NoConformersError

        if not isinstance(conformer_index, int):
            raise OpenPharmacophoreTypeError(
                "conformer_index must be of type int")

        pharmacophoric_points = []

        if isinstance(self.featdef, dict):
            for smarts_pattern, feat_name in self.featdef.items():
                if feat_name not in self.features:
                    continue
                pattern = Chem.MolFromSmarts(smarts_pattern)
                atom_indices = ligand.GetSubstructMatch(pattern)
                if len(atom_indices) == 0:
                    continue

                pharmacophoric_pnt = self.get_pharmacophoric_point(
                    ligand, feat_name, atom_indices, conformer_index,
                    self.default_radius, self.directionality)
                insort_right(pharmacophoric_points,
                             pharmacophoric_pnt,
                             key=lambda p: p.short_name)
        else:
            # Use rdkit feature factory
            chemical_features = self.featdef.GetFeaturesForMol(ligand)
            for feature in chemical_features:
                feat_name = feature.GetFamily()
                feat_name = rdkit_to_oph[feat_name]
                if feat_name not in self.features:
                    continue
                atom_indices = feature.GetAtomIds()
                pharmacophoric_pnt = self.get_pharmacophoric_point(
                    ligand, feat_name, atom_indices, conformer_index,
                    self.default_radius, self.directionality)
                insort_right(pharmacophoric_points,
                             pharmacophoric_pnt,
                             key=lambda p: p.short_name)

        return pharmacophoric_points
    def align_probe_to_target(self, probe: Chem.Mol) -> int:  # implace
        """

        :param probe: modified inplace
        :return: index of best conformer
        """
        ### find what is common
        common = self._get_common(probe)
        ### Align them
        overlap_target = self.target.GetSubstructMatch(common)
        overlap_probe = probe.GetSubstructMatch(common)
        atomMap = [
            (probe_at, target_at)
            for probe_at, target_at in zip(overlap_probe, overlap_target)
        ]
        rmss = [
            rdMolAlign.AlignMol(probe,
                                self.target,
                                prbCid=i,
                                atomMap=atomMap,
                                maxIters=500)
            for i in range(probe.GetNumConformers())
        ]
        # print(rmss)
        best_i = rmss.index(min(rmss))
        return best_i
Example #4
0
def conformer_energy(molecule: Chem.Mol, conformer_id: int = 0, 
                forcefield: str = "UFF") -> float:
    """ Get the energy of a conformer in a molecule using the universal forcefield (UFF) forcefield
        or the merck molecular forcefield (MMFF) forcefield.

        Parameters
        ----------
        molecule : rdkit.Chem.Mol
            The molecule which energy will be calculated.

        forcefield : {"UFF", "MMFF"}, optional.
            The forcefield that will be used to calculate the energy 
            (default="UFF").

        Returns
        -------
        float
            The energy of the molecule.
    """
    if molecule.GetNumConformers() == 0:
        raise NoConformersError("Molecule must have at least one conformer")

    if forcefield == "UFF":
        ff = AllChem.UFFGetMoleculeForceField(molecule, confId=conformer_id)
    elif forcefield == "MMFF":
        props = AllChem.MMFFGetMoleculeProperties(molecule)
        ff = AllChem.MMFFGetMoleculeForceField(molecule, props, confId=conformer_id)

    return ff.CalcEnergy()
Example #5
0
 def mol_to_mutliconformer_file(rdkit_mol: Chem.Mol,
                                file_name: str) -> None:
     """
     Write the rdkit molecule to a multi conformer file.
     Args:
         rdkit_mol:
             A complete Chem.Mol instance of a molecule.
         file_name:
             Name of the file to be created.
     """
     file_path = Path(file_name)
     # get the file block writer
     if file_path.suffix == ".pdb":
         writer = Chem.MolToPDBBlock
     elif file_path.suffix == ".mol" or file_path.suffix == ".sdf":
         writer = Chem.MolToMolBlock
     elif file_path.suffix == ".xyz":
         writer = Chem.MolToXYZBlock
     else:
         raise FileTypeError(
             f"The file type {file_path.suffix} is not supported please chose from xyz, pdb, mol or sdf."
         )
     with open(file_name, "w") as out:
         for i in range(rdkit_mol.GetNumConformers()):
             out.write(writer(rdkit_mol, confId=i))
Example #6
0
def write_conformers_to_xyz(molecule: Mol, path: str, max_num: Optional[int] = None) -> None:
    num_samples = molecule.GetNumConformers()
    count = num_samples if max_num is None else min(num_samples, max_num)
    string = ''
    for conf_id in range(count):
        string += conformer_to_xyz(molecule, conf_id=conf_id)
        string += '\n'

    with open(path, mode='w') as f:
        f.write(string)
Example #7
0
def MolToPixmap(mol: Mol, size: QSize):
    if size.isNull() or mol is None:
        return QPixmap()

    if not mol.GetNumConformers():
        rdDepictor.Compute2DCoords(mol)

    svg_drawer = rdMolDraw2D.MolDraw2DSVG(size.width(), size.height())
    svg_drawer.drawOptions().clearBackground = False
    svg_drawer.DrawMolecule(mol)
    svg_drawer.FinishDrawing()
    drawing_text = svg_drawer.GetDrawingText()
    return SvgToPixmap(drawing_text, size)
Example #8
0
def view_conformers(molecule: Chem.Mol) -> nv.NGLWidget:
    """
    Generate a view of the conformers of a molecule.

    Parameters
    -----------
    molecule : rdkit.Chem.Mol
        The molecule which conformers will be visualized.

    Returns
    ----------
    view : nglview.widget.NGLWidget
    """
    view = nv.NGLWidget()
    for conformer in range(molecule.GetNumConformers()):
        mol_string = Chem.MolToMolBlock(molecule, confId=conformer)
        temp_mol = Chem.MolFromMolBlock(mol_string, removeHs=False)
        component = view.add_component(temp_mol)
        component.clear()
        component.add_ball_and_stick(multipleBond=True)
    return view
Example #9
0
    def _from_mol_to_ani_input(self, mol: Chem.Mol, enforceChirality: bool):
        """
        Helper function - does not need to be called directly.
        Generates ANI input from a rdkit mol object
        """

        # generate atom list
        atom_list = []
        for a in mol.GetAtoms():
            atom_list.append(a.GetSymbol())

        if ("S" in atom_list or "P" in atom_list or "Cl" in atom_list
                or "Br" in atom_list or "I" in atom_list):
            raise NotImplementedError("Atom not yet included in ANI.")
        # generate conformations
        mol = self._generate_conformations_from_mol(mol,
                                                    self.nr_of_conformations,
                                                    enforceChirality)
        # generate coord list
        coord_list = []

        # add conformations to coord_list
        for conf_idx in range(mol.GetNumConformers()):
            tmp_coord_list = []
            for a in mol.GetAtoms():
                pos = mol.GetConformer(conf_idx).GetAtomPosition(a.GetIdx())
                tmp_coord_list.append([pos.x, pos.y, pos.z])
            coord_list.append(tmp_coord_list)
        coord_list = np.asarray(coord_list)
        assert coord_list.shape == (mol.GetNumConformers(), mol.GetNumAtoms(),
                                    3)
        coord_list *= unit.angstrom

        # generate bond list
        bond_list = []
        for b in mol.GetBonds():
            a1 = b.GetBeginAtom()
            a2 = b.GetEndAtom()
            bond_list.append((a1.GetIdx(), a2.GetIdx()))

        # get mdtraj topology
        n = random.randint(1, 10000000)
        # TODO: use tmpfile for this https://stackabuse.com/the-python-tempfile-module/ or io.StringIO
        _ = write_pdb(mol, f"tmp{n}.pdb")
        topology = md.load(f"tmp{n}.pdb").topology
        os.remove(f"tmp{n}.pdb")

        ani_input = {
            "ligand_atoms": "".join(atom_list),
            "ligand_coords": coord_list,
            "ligand_topology": topology,
            "ligand_bonds": bond_list,
        }

        # generate ONE ASE object if thermocorrections are needed
        ase_atom_list = []
        for e, c in zip(ani_input["ligand_atoms"], coord_list[0]):
            c_list = (
                c[0].value_in_unit(unit.angstrom),
                c[1].value_in_unit(unit.angstrom),
                c[2].value_in_unit(unit.angstrom),
            )
            ase_atom_list.append(Atom(e, c_list))

        mol = Atoms(ase_atom_list)
        ani_input["ase_mol"] = mol
        return ani_input