def rotor_conformer(self, *rotor_args, algo="WeightedRotorSearch", forcefield="mmff94"): """ Conformer search based on several Rotor Search algorithms of openbabel. If the input molecule is not 3D, make3d will be called (generate 3D structure, add hydrogen, a quick localopt). All hydrogen atoms need to be made explicit. Args: rotor_args: pass args to Rotor Search in openbabel. for "WeightedRotorSearch": (conformers, geomSteps, sampleRingBonds-default False) for "SystematicRotorSearch": (geomSteps-default 2500, sampleRingBonds-default False) for "RandomRotorSearch": (conformers, geomSteps-default 2500, sampleRingBonds-default False) algo (str): Default is "WeightedRotorSearch". Options are "SystematicRotorSearch", "RandomRotorSearch", and "WeightedRotorSearch". forcefield (str): Default is mmff94. Options are 'gaff', 'ghemical', 'mmff94', 'mmff94s', and 'uff'. """ if self._obmol.GetDimension() != 3: self.make3d() else: self.add_hydrogen() ff = ob.OBForceField_FindType(forcefield) if ff == 0: warnings.warn("This input forcefield {} is not supported " "in openbabel. The forcefield will be reset as " "default 'mmff94' for now.".format(forcefield)) ff = ob.OBForceField_FindType("mmff94") try: rotor_search = getattr(ff, algo) except AttributeError: warnings.warn("This input conformer search algorithm {} is not " "supported in openbabel. Options are " "'SystematicRotorSearch', 'RandomRotorSearch' " "and 'WeightedRotorSearch'. " "The algorithm will be reset as default " "'WeightedRotorSearch' for now.".format(algo)) rotor_search = ff.WeightedRotorSearch rotor_search(*rotor_args) ff.GetConformers(self._obmol)
def run_confab(mol, rmsd_cutoff=0.5, conf_cutoff=100000, energy_cutoff=50.0, confab_verbose=False): """ Generate ensemble of conformers to perform calculations on :param mol: initial molecule to generate conformers from :param rmsd_cutoff: similarity threshold for conformers, default: 0.5 :param conf_cutoff: max number of conformers to generate, default: 100,000 :param energy_cutoff: max relative energy between conformers, default: 50 :param confab_verbose: whether confab should report on rotors :type mol: openbabel.OBMol :type rmsd_cutoff: float :type conf_cutoff: int :type energy_cutoff: float :type confab_verbose: bool :return: list of conformers for a given molecule :rtype: openbabel.OBMol """ pff = ob.OBForceField_FindType("mmff94") pff.Setup(mol) pff.DiverseConfGen(rmsd_cutoff, conf_cutoff, energy_cutoff, confab_verbose) pff.GetConformers(mol) return mol
def confab_conformers(self, forcefield="mmff94", freeze_atoms=None, rmsd_cutoff=0.5, energy_cutoff=50.0, conf_cutoff=100000, verbose=False): """ Conformer generation based on Confab to generate all diverse low-energy conformers for molecules. This is different from rotor_conformer or gen3d_conformer as it aims to not simply to find a low energy conformation but to generate several different conformations. Args: forcefield (str): Default is mmff94. Options are 'gaff', 'ghemical', 'mmff94', 'mmff94s', and 'uff'. freeze_atoms ([int]): index of atoms to be freezed when performing conformer search, default is None. rmsd_cutoff (float): rmsd_cufoff, default is 0.5 Angstrom. energy_cutoff (float): energy_cutoff, default is 50.0 kcal/mol. conf_cutoff (float): max number of conformers to test, default is 1 million. verbose (bool): whether to display information on torsions found, default is False. Returns: (list): list of pymatgen Molecule objects for generated conformers. """ if self._obmol.GetDimension() != 3: self.make3d() else: self.add_hydrogen() ff = ob.OBForceField_FindType(forcefield) if ff == 0: print("Could not find forcefield {} in openbabel, the forcefield " "will be reset as default 'mmff94'".format(forcefield)) ff = ob.OBForceField_FindType("mmff94") if freeze_atoms: print('{} atoms will be freezed'.format(len(freeze_atoms))) constraints = ob.OBFFConstraints() for atom in ob.OBMolAtomIter(self._obmol): atom_id = atom.GetIndex() + 1 if id in freeze_atoms: constraints.AddAtomConstraint(atom_id) ff.SetConstraints(constraints) # Confab conformer generation ff.DiverseConfGen(rmsd_cutoff, conf_cutoff, energy_cutoff, verbose) ff.GetConformers(self._obmol) # Number of conformers generated by Confab conformer generation conformer_num = self._obmol.NumConformers() conformers = [] for i in range(conformer_num): self._obmol.SetConformer(i) conformer = copy.deepcopy( BabelMolAdaptor(self._obmol).pymatgen_mol) conformers.append(conformer) self._obmol.SetConformer(0) return conformers
def generate_limited_rotamer_set( input_path, output_path, atoms_to_unfreeze, output_format='mol2', include_input_conformation_in_output=True, # Note: the Confab settings below (rmsd_cutoff, conf_cutoff, energy_cutoff, verbose) # are currently set to the default values from Confab. # You you might need to change these for your project. rmsd_cutoff=0.5, conf_cutoff=10000, energy_cutoff=25.0, confab_verbose=True): assert (output_path.endswith(output_format)) assert (os.path.isfile(input_path)) mol = read_molecules(input_path, single=True) # force field for open babel applied - mmff94 pff = ob.OBForceField_FindType("mmff94") assert (pff.Setup(mol)) # Make sure setup works OK count_aromatic_bonds(mol) print("Molecule " + mol.GetTitle()) print("Number of rotatable bonds = " + str(mol.NumRotors())) if len(atoms_to_unfreeze) > 0: print('%d atoms will be allowed to move; freezing others' % len(atoms_to_unfreeze)) constraints = ob.OBFFConstraints() for atom in ob.OBMolAtomIter(mol): atom_id = atom.GetIndex() + 1 if atom_id not in atoms_to_unfreeze: constraints.AddAtomConstraint(atom_id) pff.SetConstraints(constraints) # Run Confab conformer generation pff.DiverseConfGen(rmsd_cutoff, conf_cutoff, energy_cutoff, confab_verbose) pff.GetConformers(mol) if include_input_conformation_in_output: confs_to_write = mol.NumConformers() else: confs_to_write = mol.NumConformers() - 1 print("Generated %d conformers total (%d will be written)" % (mol.NumConformers(), confs_to_write)) obconversion = ob.OBConversion() obconversion.SetOutFormat(output_format) output_strings = [] for conf_num in range(confs_to_write): mol.SetConformer(conf_num) output_strings.append(obconversion.WriteString(mol)) print('Writing %d conformations to %s' % (len(output_strings), output_path)) with open(output_path, 'w') as f: for output_string in output_strings: f.write(output_string)