def generateConformers(self, num_confs=400, optimizemode="mmff", align=True, append=True): """ Generates ligand conformers Parameters ---------- num_confs: int Number of conformers to generate. optimizemode: str The optimizemode to use. Can be 'uff', 'mmff' Default: 'mmff' align: bool If True, the conformer are aligned to the first one Default: True append: bool If False, the current conformers are deleted Default: True """ from rdkit.Chem.AllChem import ( UFFOptimizeMolecule, MMFFOptimizeMolecule, EmbedMultipleConfs, ) from rdkit.Chem.rdMolAlign import AlignMolConformers if not append: self.dropFrames(np.arange(self.numFrames)) # get the rdkit mol and copy it. mol = deepcopy(self._mol) # hydrogens are added for safety mol = Chem.AddHs(mol) # generating conformations ids = EmbedMultipleConfs( mol, clearConfs=False, numConfs=num_confs, pruneRmsThresh=1.0, maxAttempts=10000, ) if optimizemode not in ["uff", "mmff"]: raise ValueError('Unknown optimizemode. Should be "uff", "mmff"') # optimizing conformations depends on the optimizemode passed for id in ids: if optimizemode == "mmff": MMFFOptimizeMolecule(mol, confId=id) elif optimizemode == "uff": UFFOptimizeMolecule(mol, confId=id) if align: AlignMolConformers(mol) self._mol = mol
def generate(self, max_generated_conformers=50, prune_thresh=0.01, maxattempts_per_conformer=5, output=None, threads=1): ''' Generates conformers Note the number max_generated _conformers required is related to the number of rotatable bonds ''' self.mol = AddHs(self.mol, addCoords=True) self.initial_confs = EmbedMultipleConfs( self.mol, numConfs=max_generated_conformers, pruneRmsThresh=prune_thresh, maxAttempts=maxattempts_per_conformer, useRandomCoords=False, # Despite what the documentation says -1 is a seed!! # It doesn't mean random generation numThreads=threads, randomSeed=random.randint(1, 10000000)) if len(self.initial_confs) == 0: output.write((f"Generated {len(self.initial_confs)} " "initial confs\n")) output.write((f"Trying again with {max_generated_conformers * 10} " "attempts and random coords\n")) self.initial_confs = EmbedMultipleConfs( self.mol, numConfs=max_generated_conformers, pruneRmsThresh=prune_thresh, useRandomCoords=True, maxAttempts=10 * maxattempts_per_conformer, # Despite what the documentation says -1 is a seed!! # It doesn't mean random # generatrion numThreads=threads, randomSeed=random.randint(1, 10000000)) output.write("Generated " + str(len(self.initial_confs)) + " initial confs\n") return self.initial_confs
def gen_conformers(mol, num_confs=DEF_MAX_CONFS, max_attempts=1000, prune_rms_thresh=0.025, use_exp_torsion_angle_prefs=True, use_basic_knowledge=True, enforce_chirality=True): ids = EmbedMultipleConfs( mol, numConfs=num_confs, maxAttempts=max_attempts, pruneRmsThresh=prune_rms_thresh, useExpTorsionAnglePrefs=use_exp_torsion_angle_prefs, useBasicKnowledge=use_basic_knowledge, enforceChirality=enforce_chirality, numThreads=0, randomSeed=10) return list(ids)
def ConstrainedEmbedMultipleConfs( mol, core, numConfs=10, useTethers=True, coreConfId=-1, randomseed=2342, getForceField=UFFGetMoleculeForceField, **kwargs, ): """ Function to obtain multiple constrained embeddings per molecule. This was taken as is from: from https://github.com/rdkit/rdkit/issues/3266 :param mol: RDKit molecule object to be embedded. :param core: RDKit molecule object of the core used as constrained. Needs to hold at least one conformer coordinates. :param numCons: Number of conformations to create :param useTethers: (optional) boolean whether to pull embedded atoms to core coordinates, see rdkit.Chem.AllChem.ConstrainedEmbed :param coreConfId: (optional) id of the core conformation to use :param randomseed: (optional) seef for the random number generator :param getForceField: (optional) force field to use for the optimization of molecules :return: RDKit molecule object containing the embedded conformations. """ match = mol.GetSubstructMatch(core) if not match: raise ValueError("molecule doesn't match the core") coordMap = {} coreConf = core.GetConformer(coreConfId) for i, idxI in enumerate(match): corePtI = coreConf.GetAtomPosition(i) coordMap[idxI] = corePtI cids = EmbedMultipleConfs(mol, numConfs=numConfs, coordMap=coordMap, randomSeed=randomseed, **kwargs) cids = list(cids) if len(cids) == 0: raise ValueError('Could not embed molecule.') algMap = [(j, i) for i, j in enumerate(match)] if not useTethers: # clean up the conformation for cid in cids: ff = getForceField(mol, confId=cid) for i, idxI in enumerate(match): for j in range(i + 1, len(match)): idxJ = match[j] d = coordMap[idxI].Distance(coordMap[idxJ]) ff.AddDistanceConstraint(idxI, idxJ, d, d, 100.) ff.Initialize() n = 4 more = ff.Minimize() while more and n: more = ff.Minimize() n -= 1 # rotate the embedded conformation onto the core: rms = AlignMol(mol, core, atomMap=algMap) else: # rotate the embedded conformation onto the core: for cid in cids: rms = AlignMol(mol, core, prbCid=cid, atomMap=algMap) ff = getForceField(mol, confId=cid) conf = core.GetConformer() for i in range(core.GetNumAtoms()): p = conf.GetAtomPosition(i) pIdx = ff.AddExtraPoint(p.x, p.y, p.z, fixed=True) - 1 ff.AddDistanceConstraint(pIdx, match[i], 0, 0, 100.) ff.Initialize() n = 4 more = ff.Minimize(energyTol=1e-4, forceTol=1e-3) while more and n: more = ff.Minimize(energyTol=1e-4, forceTol=1e-3) n -= 1 # realign rms = AlignMol(mol, core, prbCid=cid, atomMap=algMap) return mol