def get_parameter_handler_from_forcefield(self, parameter_handler_name, forcefield): """ It returns a parameter handler from the forcefield based on its name. Parameters ---------- parameter_handler_name : str The name of the parameter handler that is requested forcefield : an openforcefield.typing.engines.smirnoff.ForceField object The forcefield from which the parameter handler will be obtained Returns ------- parameter_handler : an openforcefield.typing.engines.smirnoff.parameters.ParameterHandler object The ParameterHandler that was requested """ from openforcefield.typing.engines.smirnoff import ForceField if isinstance(forcefield, str): forcefield = ForceField(forcefield) elif isinstance(forcefield, ForceField): pass else: raise Exception('Invalid forcefield type') return forcefield.get_parameter_handler(parameter_handler_name)
def mock_force_field(parameters: List[SMIRNOFFParameter]): """Mock a ForceBalance forcefield directory.""" # Create the force field directory. force_field = ForceField("openff-1.2.0.offxml") parameters_to_fit = defaultdict(lambda: defaultdict(list)) for parameter in parameters: parameters_to_fit[parameter.handler][parameter.smirks].append( parameter.attribute) for handler_name in parameters_to_fit: handler = force_field.get_parameter_handler(handler_name) for smirks in parameters_to_fit[handler_name]: openff_parameter = handler.parameters[smirks] attributes_string = ", ".join( parameters_to_fit[handler_name][smirks]) openff_parameter.add_cosmetic_attribute("parameterize", attributes_string) os.makedirs("forcefield", exist_ok=True) force_field.to_file(os.path.join("forcefield", "forcefield.offxml"))
def test_force_field_custom_handler(mock_entry_point_plugins): """Tests a force field can make use of a custom parameter handler registered through the entrypoint plugin system. """ # Construct a simple FF which only uses the custom handler. force_field_contents = "\n".join([ "<?xml version='1.0' encoding='ASCII'?>", "<SMIRNOFF version='0.3' aromaticity_model='OEAroModel_MDL'>", " <CustomHandler version='0.3'></CustomHandler>", "</SMIRNOFF>" ]) # An exception should be raised when plugins aren't allowed. with pytest.raises(KeyError) as error_info: ForceField(force_field_contents) assert ( "Cannot find a registered parameter handler class for tag 'CustomHandler'" in error_info.value.args[0]) # Otherwise the FF should be created as expected. force_field = ForceField(force_field_contents, load_plugins=True) parameter_handler = force_field.get_parameter_handler("CustomHandler") assert parameter_handler is not None assert parameter_handler.__class__.__name__ == "CustomHandler"
def test_adding_params_parameterize_flag(): """ Test adding new smirks patterns with cosmetic attributes. """ ff = ForceFieldEditor(forcefield_name="openff-1.0.0.offxml") # add an atom smirks for boron boron = AtomSmirks(smirks="[#5:1]", parameterize={"epsilon"}, atoms={(0,)}, epsilon=0.04, rmin_half=3) # add boron with the flag ff.add_smirks(smirks=[boron, ], parameterize=True) with temp_directory(): ff.forcefield.to_file(filename="boron.offxml") # this should fail if the flag was added with pytest.raises(SMIRNOFFSpecError): _ = ForceField("boron.offxml", allow_cosmetic_attributes=False) boron_ff = ForceField("boron.offxml", allow_cosmetic_attributes=True) # now look for the parameter we added boron_param = boron_ff.get_parameter_handler( "vdW" ).parameters["[#5:1]"] # now make sure it has the param flag param_dict = boron_param.__dict__ assert param_dict["_cosmetic_attribs"] == ["parameterize"] assert param_dict["_parameterize"] == "epsilon"
def serialise_system(self): """Create the OpenMM system; parametrise using frost; serialise the system.""" # Load the molecule using openforcefield pdb_file = app.PDBFile(f'{self.molecule.name}.pdb') # Now we need the connection info try using smiles string from rdkit rdkit = RDKit() molecule = Molecule.from_smiles( rdkit.get_smiles(f'{self.molecule.name}.pdb')) # Make the openMM system omm_topology = pdb_file.topology off_topology = Topology.from_openmm(omm_topology, unique_molecules=[molecule]) # Load the smirnoff99Frosst force field. forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml') # Parametrize the topology and create an OpenMM System. system = forcefield.create_openmm_system(off_topology) # Serialise the OpenMM system into the xml file with open('serialised.xml', 'w+') as out: out.write(XmlSerializer.serializeSystem(system))
def min_ffxml(mol, ffxml): # make copy of the input mol oe_mol = oechem.OEGraphMol(mol) try: # create openforcefield molecule ==> prone to triggering Exception off_mol = Molecule.from_openeye(oe_mol) # load in force field ff = ForceField(ffxml) # create components for OpenMM system topology = Topology.from_molecules(molecules=[off_mol]) # create openmm system ==> prone to triggering Exception #system = ff.create_openmm_system(topology, charge_from_molecules=[off_mol]) system = ff.create_openmm_system(topology) except Exception as e: smilabel = oechem.OEGetSDData(oe_mol, "SMILES QCArchive") print( ' >>> openforcefield failed to create OpenMM system: ' f"'{oe_mol.GetTitle()}' '{smilabel}'") print(f"{e}\n") return print(" >>> successful OpenMM system creation for openforcefield " f"mol \"{oe_mol.GetTitle()}\"")
def openff(self): # Load the molecule (for now mol2, until charges are saved on sdf) molecule = Molecule.from_file(self.lig + '.mol2') topology = Topology.from_molecules([molecule]) # Label using the smirnoff99Frosst force field self.forcefield = ForceField('smirnoff99Frosst.offxml') self.parameters = self.forcefield.label_molecules(topology)[0]
def checkTorsion(smiles, torsion_indices, ff_name): """ Take mollist and check if the molecules in a list match a specific torsion id Parameters ---------- molList : List of objects List of oemols with datatags generated in genData function Returns ------- molList : list of objects List of oemol objects that have a datatag "IDMatch" that contain the torsion id involved in the QCA torsion drive """ matches = [] count = 0 mols = [] #tid='' #molecule = Molecule.from_mapped_smiles(smiles) print(smiles) from openeye import oechem # create a new molecule #mol = oechem.OEGraphMol() # convert the SMILES string into a molecule #oechem.OESmilesToMol(mol,smiles) #molecule = Molecule.from_smiles(smiles) #molecule=Molecule.from_openeye(mol) molecule = Molecule.from_mapped_smiles(smiles) topology = Topology.from_molecules(molecule) # Let's label using the Parsley force field forcefield = ForceField(ff_name, allow_cosmetic_attributes=True) # Run the molecule labeling molecule_force_list = forcefield.label_molecules(topology) params = [] indices = [] # Print out a formatted description of the torsion parameters applied to this molecule for mol_idx, mol_forces in enumerate(molecule_force_list): # print(f'Forces for molecule {mol_idx}') for force_tag, force_dict in mol_forces.items(): if force_tag == "ProperTorsions": for (atom_indices, parameter) in force_dict.items(): params.append(parameter.id) indices.append(atom_indices) #torsion_indices=tuple(torsion_indices) #print(type(torsion_indices)) print(torsion_indices) #print(type(atom_indices)) print(atom_indices) if atom_indices == torsion_indices or tuple( reversed(atom_indices)) == torsion_indices: #mol.SetData("IDMatch", parameter.id) tid = parameter.id print(params) print(indices) return tid
def get_assigned_torsion_param(tdentry, forcefield): """Get the OpenFF forcefield torsion parameter ultimately assigned to the given TorsionDrive entry's torsion dihedral. Parameters ---------- tdentry : TDEntry TDEntry (TorsionDrive entry) to operate on; will be used to generate molecule, extract dihedral indices driven. forcefield : str, ForceField OpenFF forcefield to apply. Returns ------- torsion_params : ProperTorsion Dict-like object with attributes giving the applied torsion parameters Examples -------- Starting with TDEntries from usage of `get_torsiondrives_matching_smarts` (see its Example), we can get back the parameter assigned to this by, say `"openff-1.0.0.offxml"`: >>> from openforcefield.typing.engines.smirnoff import ForceField >>> tdentries = get_torsiondrives_matching_smarts(smarts, dataset, client) >>> ff = ForceField('openff-1.0.0.offxml') >>> assigned = [smarts_torsions.get_assigned_torsion_param(tdentry, ff) for tdentry in tdentries] >>> print([t.id for t in assigned]) ['t47', 't47', 't47', 't47', ...] """ mol_smiles = tdentry.attributes["canonical_isomeric_explicit_hydrogen_mapped_smiles"] offmol = Molecule.from_mapped_smiles(mol_smiles) if isinstance(forcefield, str): forcefield = ForceField(forcefield) # apply forcefield parameters topology = Topology.from_molecules(offmol) # we only have one molecule by definition here, so extracting 0th molecule_forces = forcefield.label_molecules(topology)[0] # by convention, we only have one driven torsion # would need to revisit if we are working with 2D torsions dihedral_indices = tdentry.td_keywords.dihedrals[0] # get torsion parameters corresponding to dihedral indices torsions = molecule_forces["ProperTorsions"] torsion_params = torsions.get(dihedral_indices) # if None, try reversing it if torsion_params is None: torsion_params = torsions[dihedral_indices[::-1]] return torsion_params
def minimise_energy_all_confs(mol, models = None, epsilon = 4, allow_undefined_stereo = True, **kwargs ): from simtk import unit from simtk.openmm import LangevinIntegrator from simtk.openmm.app import Simulation, HBonds, NoCutoff from rdkit import Chem from rdkit.Geometry import Point3D import mlddec import copy import tqdm mol = Chem.AddHs(mol, addCoords = True) if models is None: models = mlddec.load_models(epsilon) charges = mlddec.get_charges(mol, models) from openforcefield.utils.toolkits import RDKitToolkitWrapper, ToolkitRegistry from openforcefield.topology import Molecule, Topology from openforcefield.typing.engines.smirnoff import ForceField # from openforcefield.typing.engines.smirnoff.forcefield import PME import parmed import numpy as np forcefield = ForceField(get_data_filename("modified_smirnoff99Frosst.offxml")) #FIXME better way of identifying file location tmp = copy.deepcopy(mol) tmp.RemoveAllConformers() #XXX workround for speed beacuse seemingly openforcefield records all conformer informations, which takes a long time. but I think this is a ill-practice molecule = Molecule.from_rdkit(tmp, allow_undefined_stereo = allow_undefined_stereo) molecule.partial_charges = unit.Quantity(np.array(charges), unit.elementary_charge) topology = Topology.from_molecules(molecule) openmm_system = forcefield.create_openmm_system(topology, charge_from_molecules= [molecule]) structure = parmed.openmm.topsystem.load_topology(topology.to_openmm(), openmm_system) system = structure.createSystem(nonbondedMethod=NoCutoff, nonbondedCutoff=1*unit.nanometer, constraints=HBonds) integrator = LangevinIntegrator(273*unit.kelvin, 1/unit.picosecond, 0.002*unit.picoseconds) simulation = Simulation(structure.topology, system, integrator) out_mol = copy.deepcopy(mol) for i in tqdm.tqdm(range(out_mol.GetNumConformers())): conf = mol.GetConformer(i) structure.coordinates = unit.Quantity(np.array([np.array(conf.GetAtomPosition(i)) for i in range(mol.GetNumAtoms())]), unit.angstroms) simulation.context.setPositions(structure.positions) simulation.minimizeEnergy() # simulation.step(1) coords = simulation.context.getState(getPositions = True).getPositions(asNumpy = True).value_in_unit(unit.angstrom) conf = out_mol.GetConformer(i) for j in range(out_mol.GetNumAtoms()): conf.SetAtomPosition(j, Point3D(*coords[j])) return out_mol
def paramUsage(smilesList, offxml): """ Description - Reads in list of smiles and returns a dictionary of .offxml style parameters as keys and smiles of molecules as items Input - smilesList: A list of smiles offxml: The .offxml format force field that the parameters will be used with Return - anglebondDict: A dictionary of .offxml style parameters as keys and smiles of molecules that utilize parameters. The returned dictionary is only for bond and angle parameters e.g. 'a1', 'b2', etc. Note: The function can be modified to return a dictionary of torsion parameters. """ # Initialize storage torsionDict = dict() anglebondDict = dict() # Let's label using our RC force field forcefield = ForceField(offxml) # Loop over smiles for smi in smilesList: # Create a simple molecule from SMILES and turn it into a topology. molecule = Molecule.from_smiles(smi, allow_undefined_stereo = True) topology = Topology.from_molecules([molecule]) # Run the molecule labeling molecule_force_list = forcefield.label_molecules(topology) # Print out a formatted description of the parameters applied to this molecule for mol_idx, mol_forces in enumerate(molecule_force_list): for force_tag, force_dict in mol_forces.items(): for (atom_indices, parameter) in force_dict.items(): pid = parameter.id #create two seperate parameter usage dictionaries for (1) angle and bonds and (2) torsions if "a" in pid or "b" in pid: if not pid in anglebondDict: anglebondDict[pid] = set() anglebondDict[pid].add(smi) #Uncomment this for torsion dictionary #if "t" in pid: # if not pid in torsionDict: # torsionDict[pid] = set() # torsionDict[pid].add(smi) #Write out the angle and bond dictionary to "anglebond.p" file pickle.dump(anglebondDict, open( "anglebond.p", "wb" ) ) return anglebondDict
def build_context(offxml, molfile): """ Build an OpenMM Context from a offxml file and a molecule file """ forcefield = ForceField(offxml, allow_cosmetic_attributes=True) molecule = OffMolecule.from_file(molfile) system = forcefield.create_openmm_system(molecule.to_topology()) integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds) platform = openmm.Platform.getPlatformByName('Reference') context = openmm.Context(system, integrator, platform) return context
def load_forcefield(forcefield="openff_unconstrained-1.1.0"): # get a forcefield try: ff = ForceField("%s.offxml" % forcefield) except: try: ff = ForceField("test_forcefields/%s.offxml" % forcefield) except: raise NotImplementedError return ff
def create_openmm_system(conversion, molecules): """ Create an OpenMM system using the input MOL2 file and force field file. """ molecule = Molecule.from_openeye(molecules[0]) topology = Topology.from_molecules([molecule]) ff = ForceField(conversion.ff) system = ff.create_openmm_system(topology) return topology, system
def update_simulation(self, **kwargs): """ Create the simulation object, or update the force field parameters in the existing simulation object. This should be run when we write a new force field XML file. """ if len(kwargs) > 0: self.simkwargs = kwargs self.mod = Modeller(self.pdb.topology, self.pdb.positions) self.forcefield = ForceField(*self.offxml) # This part requires the OpenEye tools but may be replaced # by RDKit when that support comes online. oemols = [] for fnm in self.mol2_files: mol = oechem.OEGraphMol() ifs = oechem.oemolistream(fnm) oechem.OEReadMolecule(ifs, mol) oechem.OETriposAtomNames(mol) oemols.append(mol) self.system = self.forcefield.createSystem(self.pdb.topology, oemols, **self.mmopts) # Commenting out all virtual site stuff for now. # self.vsinfo = PrepareVirtualSites(self.system) self.nbcharges = np.zeros(self.system.getNumParticles()) for i in self.system.getForces(): if isinstance(i, NonbondedForce): self.nbcharges = np.array([ i.getParticleParameters(j)[0]._value for j in range(i.getNumParticles()) ]) if self.SetPME: i.setNonbondedMethod(i.PME) if isinstance(i, AmoebaMultipoleForce): if self.SetPME: i.setNonbondedMethod(i.PME) #---- # If the virtual site parameters have changed, # the simulation object must be remade. #---- # vsprm = GetVirtualSiteParameters(self.system) # if hasattr(self,'vsprm') and len(self.vsprm) > 0 and np.max(np.abs(vsprm - self.vsprm)) != 0.0: # if hasattr(self, 'simulation'): # delattr(self, 'simulation') # self.vsprm = vsprm.copy() if hasattr(self, 'simulation'): UpdateSimulationParameters(self.system, self.simulation) else: self.create_simulation(**self.simkwargs)
def convert(self): # Set OEMol ifs = oemolistream() ifs.SetFlavor(OEFormat_MOL2, OEIFlavor_MOL2_Forcefield) ifs.open(self.mol2_file) # Read in molecules for i, mol in enumerate(ifs.GetOEMols()): if i > 0: raise Exception( 'Only single residue molecules are currently supported') OETriposAtomNames(mol) self.molecules.append(OEMol(mol)) # Set topology self.mol2_topo = pmd.load_file(self.mol2_file, structure=True) # Parameterize ff = ForceField('forcefield/smirnoff99Frosst.offxml') self.labels = ff.labelMolecules(self.molecules, verbose=False) self.off_system = ff.createSystem(self.mol2_topo.topology, self.molecules, nonbondedCutoff=1.1 * unit.nanometer, ewaldErrorTolerance=1e-4) # Load into Parmed self.pmd_system = pmd.openmm.topsystem.load_topology( self.mol2_topo.topology, self.off_system, self.mol2_topo.positions) # Convert to AmberParm self.parm = pmd.amber.AmberParm.from_structure(self.pmd_system) # HACKY PART!! # Amber specifies that the third atom in an improper is the central # atom, but smirnoff currently specifies the second atom. A check for # impropers was conducted during pmd.openmm.topsystem.load_topology(), # but that looked at the third atom, so we'll recheck the second atom. for i, dihedral in enumerate(cnvs.parm.dihedrals): a1 = dihedral.atom1 a2 = dihedral.atom2 a3 = dihedral.atom3 a4 = dihedral.atom4 if a1 in a2.bond_partners and a3 in a2.bond_partners and a4 in a2.bond_partners: (dihedral.atom1, dihedral.atom2, dihedral.atom3, dihedral.atom4) = (a3, a4, a2, a1) dihedral.improper = True # Create unique atom types unique_types = aimtools.unique_types.create_unique_type_list(self.parm) # Write AMBER mol2 and frcmod aimtools.unique_types.write_unique_frcmod_mol2s( self.parm, unique_types, names=self.output_prefix)
def _create_impropers_only_system( smiles: str = "CC1=C(C(=O)C2=C(C1=O)N3CC4C(C3(C2COC(=O)N)OC)N4)N", ) -> mm.System: """Create a simulation that contains only improper torsion terms, by parameterizing with openff-1.2.0 and deleting all terms but impropers """ molecule = Molecule.from_smiles(smiles, allow_undefined_stereo=True) g = esp.Graph(molecule) topology = Topology.from_molecules(molecule) forcefield = ForceField("openff-1.2.0.offxml") openmm_system = forcefield.create_openmm_system(topology) # delete all forces except PeriodicTorsionForce is_torsion = ( lambda force: "PeriodicTorsionForce" in force.__class__.__name__) for i in range(openmm_system.getNumForces())[::-1]: if not is_torsion(openmm_system.getForce(i)): openmm_system.removeForce(i) assert openmm_system.getNumForces() == 1 torsion_force = openmm_system.getForce(0) assert is_torsion(torsion_force) # set k = 0 for any torsion that's not an improper indices = set( map( tuple, esp.graphs.utils.offmol_indices.improper_torsion_indices(molecule), )) num_impropers_retained = 0 for i in range(torsion_force.getNumTorsions()): ( p1, p2, p3, p4, periodicity, phase, k, ) = torsion_force.getTorsionParameters(i) if (p1, p2, p3, p4) in indices: num_impropers_retained += 1 else: torsion_force.setTorsionParameters(i, p1, p2, p3, p4, periodicity, phase, 0.0) assert (num_impropers_retained > 0 ) # otherwise this molecule is not a useful test case! return openmm_system, topology, g
def test_sort_smirnoff_dict(): from collections import OrderedDict from openforcefield.typing.engines.smirnoff import ForceField from openforcefield.utils.utils import sort_smirnoff_dict forcefield = ForceField("test_forcefields/smirnoff99Frosst.offxml") smirnoff_dict = forcefield._to_smirnoff_data() # Ensure data is not created or destroyed # dict.__eq__ does not check order assert smirnoff_dict == OrderedDict( sort_smirnoff_dict(forcefield._to_smirnoff_data()))
def test_update_parameters(smirks_data): """ Test updating the smirks parameters using openff types. """ smirk, result = smirks_data # load a forcefield ff = ForceField("openff-1.0.0.offxml") # all input smirks have parameters set to 0 off_parameter = ff.get_parameter_handler( smirk.type).parameters[smirk.smirks] smirk.update_parameters(off_smirk=off_parameter) for param, value in result.items(): assert getattr(smirk, param) == value
def create_openmm_system_from_smiles(conversion, smiles): """ Create an OpenMM system using SMILES and force field file. """ molecule = Molecule.from_smiles(smiles) topology = Topology.from_molecules([molecule]) ff = ForceField(conversion.ff) system = ff.create_openmm_system(topology) molecule.generate_conformers(n_conformers=1) return topology, system
def checkTorsion(molList, ff_name): """ Take mollist and check if the molecules in a list match a specific torsion id Parameters ---------- molList : List of objects List of oemols with datatags generated in genData function Returns ------- molList : list of objects List of oemol objects that have a datatag "IDMatch" that contain the torsion id involved in the QCA torsion drive """ matches = [] count = 0 mols = [] for mol in molList: molecule = Molecule.from_mapped_smiles(mol.GetData("cmiles")) topology = Topology.from_molecules(molecule) # Let's label using the Parsley force field forcefield = ForceField(ff_name) # Run the molecule labeling molecule_force_list = forcefield.label_molecules(topology) params = [] # Print out a formatted description of the torsion parameters applied to this molecule for mol_idx, mol_forces in enumerate(molecule_force_list): # print(f'Forces for molecule {mol_idx}') for force_tag, force_dict in mol_forces.items(): if force_tag == "ProperTorsions": for (atom_indices, parameter) in force_dict.items(): params.append(parameter.id) if atom_indices == mol.GetData("TDindices") or tuple( reversed(atom_indices) ) == mol.GetData("TDindices"): count += 1 mol.SetData("IDMatch", parameter.id) mols.append(mol) print( "Out of " + str(len(molList)) + " molecules, " + str(count) + " were processed with checkTorsion()" ) return mols
def run_validate_single_point(ffxml, data_folder): forcefield = ForceField(ffxml, allow_cosmetic_attributes=True) ff_name = os.path.basename(ffxml) # read molecules from the data folder bench_mol_folders = sorted(os.listdir(data_folder)) print(f'\n*** Single point benchmark on QM and MM minimized geometries ***') print(f"- Number of molecules: {len(bench_mol_folders)}") print(f"- Test forcefield : {ff_name}") print(f"- Start Time : {time.ctime()}") print(f"- Unit : kcal/mol \n") print(f'{"":5s} | {"":15s} | {"QM Geometry":^47s} | {"MM Geometry":^47s}') print(f'{"#":>5s} | {"Molecule ID":15s} | {"E_release":>15s} {"E_test":>15s} {"Diff":>15s} | {"E_release":>15s} {"E_test":>15s} {"Diff":>15s}') for i, mol_fol in enumerate(bench_mol_folders): folder_path = os.path.join(data_folder, mol_fol) # read bench data from folder with open(os.path.join(folder_path, 'bench_data.pickle'), 'rb') as pfile: bench_data = pickle.load(pfile) mol2_path = os.path.join(folder_path, bench_data['mol2_fnm']) pdb_path = os.path.join(folder_path, bench_data['pdb_fnm']) positions_list = [bench_data['geo1_qm'], bench_data['geo2_mm']] ref_energies = [bench_data['energy_geo1'], bench_data['energy_geo2']] eval_energies = eval_single_point_energies(forcefield, bench_data['partial_charges'], mol2_path, pdb_path, positions_list) e_ref_geo1 = ref_energies[0].value_in_unit(unit.kilocalorie_per_mole) e_ref_geo2 = ref_energies[1].value_in_unit(unit.kilocalorie_per_mole) e_test_geo1 = eval_energies[0].value_in_unit(unit.kilocalorie_per_mole) e_test_geo2 = eval_energies[1].value_in_unit(unit.kilocalorie_per_mole) print(f'{i:5d} | {mol_fol:15s} | {e_ref_geo1:15.3f} {e_test_geo1:15.3f} {e_test_geo1-e_ref_geo1:15.3f} | {e_ref_geo2:15.3f} {e_test_geo2:15.3f} {e_test_geo2-e_ref_geo2:15.3f}')
def generateSMIRNOFFStructure(molecule): """ Given an OpenEye molecule (oechem.OEMol), create an OpenMM System and use to generate a ParmEd structure using the SMIRNOFF forcefield parameters. """ from openforcefield.typing.engines.smirnoff import ForceField from openforcefield.typing.engines.smirnoff.forcefield_utils import create_system_from_molecule ff = get_data_filename('forcefield/smirnoff99Frosst.ffxml') with open(ff) as ffxml: mol_ff = ForceField(ffxml) if not checkCharges(molecule): from openmoltools.openeye import get_charges print("Assigning charges to molecule.") charged_molecule = get_charges(molecule) else: charged_molecule = molecule mol_top, mol_sys, mol_pos = create_system_from_molecule( mol_ff, charged_molecule) molecule_structure = parmed.openmm.load_topology(mol_top, mol_sys, xyz=mol_pos) return molecule_structure
def main(): import argparse import pickle parser = argparse.ArgumentParser() parser.add_argument("dataset", help='Name of the OptimizationDataset on QCFractal') parser.add_argument( "-l", "--load_pickle", help='Load downloaded torsiondrive data from pickle file') parser.add_argument( "-t", "--test_ff_fnm", required=True, help= "Provide an offxml for testing the molecules created, skip the ones that failed" ) args = parser.parse_args() # step 1: download dataset from server if args.load_pickle: with open(args.load_pickle, 'rb') as pfile: hessian_data = pickle.load(pfile) print( f"{len(hessian_data)} hessian data entries loaded from {args.load_pickle}" ) else: hessian_data = download_hessian_data(args.dataset) # step 2: filter the dataset, keep one lowest energy for each molecule hessian_data = filter_hessian_data(hessian_data) # create a ForceField object for testing test_ff = ForceField(args.test_ff_fnm) # step 3: generate one target for each data entry make_vib_freq_target(args.dataset, hessian_data, test_ff=test_ff)
def main(): import argparse import pickle parser = argparse.ArgumentParser() parser.add_argument("dataset", help='Name of the OptimizationDataset on QCFractal') parser.add_argument( "-l", "--load_pickle", help='Load downloaded torsiondrive data from pickle file') parser.add_argument( "-t", "--test_ff_fnm", required=True, help= "Provide an offxml for testing the molecules created, skip the ones that failed" ) args = parser.parse_args() if args.load_pickle: with open(args.load_pickle, 'rb') as pfile: torsiondrive_data = pickle.load(pfile) else: torsiondrive_data = download_torsiondrive_data(args.dataset) # require the test_ff for metadata test_ff = ForceField(args.test_ff_fnm) make_torsiondrive_target(args.dataset, torsiondrive_data, test_ff=test_ff)
def min_ffxml(mol, ofs, ffxml): """ Minimize the mol with force field input from FFXML file. Parameters ---------- mol : OpenEye single-conformer molecule ofs : OpenEye output filestream ffxml : string name of FFXML file """ # make copy of the input mol oe_mol = oechem.OEGraphMol(mol) try: # create openforcefield molecule ==> prone to triggering Exception off_mol = Molecule.from_openeye(oe_mol) # load in force field ff = ForceField(ffxml) # create components for OpenMM system topology = Topology.from_molecules(molecules=[off_mol]) # create openmm system ==> prone to triggering Exception #system = ff.create_openmm_system(topology, charge_from_molecules=[off_mol]) system = ff.create_openmm_system(topology) except Exception as e: smilabel = oechem.OEGetSDData(oe_mol, "SMILES QCArchive") print( ' >>> openforcefield failed to create OpenMM system: ' f'{oe_mol.GetTitle()} {smilabel}: {e}') return positions = structure.extractPositionsFromOEMol(oe_mol) # minimize structure with ffxml newpos, energy = run_openmm(topology, system, positions) # save geometry, save energy as tag, write mol to file oe_mol.SetCoords(oechem.OEFloatArray(newpos)) oechem.OESetSDData(oe_mol, "Energy FFXML", str(energy)) oechem.OEWriteConstMolecule(ofs, oe_mol) return
def make_optgeo_target(dataset_name, final_molecules, size=None, test_ff_fnm=None): # create the ff for testing if test_ff_fnm != None: from openforcefield.typing.engines.smirnoff import ForceField test_ff = ForceField(test_ff_fnm, allow_cosmetic_attributes=True) else: test_ff = None n_molecules = len(final_molecules) if n_molecules == 0: print("No molecules found") return # create and cd into targets folder if not os.path.exists('targets'): os.mkdir('targets') os.chdir('targets') if size is None or n_molecules <= size: # put all molecules into one target target_name = 'optgeo_' + dataset_name.replace(' ', '_') n_success = create_target(target_name, final_molecules) target_names = [target_name] else: assert size > 0 and isinstance(size, int), 'size should be positive int' n_groups = (n_molecules + size - 1) // size # put molecules into separate targets all_molelcule_idxs = list(final_molecules.keys()) target_names = [] idx_fmt_string = get_int_fmt_string(n_groups) n_success = 0 for i_g in range(n_groups): group_molecule_idxs = all_molelcule_idxs[i_g * size:(i_g + 1) * size] molecules_data = { m_index: final_molecules[m_index] for m_index in group_molecule_idxs } target_name = 'optgeo_' + dataset_name.replace( ' ', '_') + '-' + idx_fmt_string.format(i_g) this_n_success = create_target(target_name, molecules_data, test_ff=test_ff, start_idx=i_g * size) if this_n_success > 0: target_names.append(target_name) n_success += this_n_success print(f"Successfully created targets with total {n_success} molecules") # write a targets.in file target_in_fnm = f"targets.in.{dataset_name.replace(' ', '_')}" with open(target_in_fnm, 'w') as outfile: for target_name in target_names: outfile.write(target_opts.format(name=target_name)) os.chdir('..') print(f"Targets generation finished!") print( f"You can copy contents in {os.path.join('targets', target_in_fnm)} to your ForceBalance input file." )
def main(): import pickle forcefield = ForceField('result.offxml', allow_cosmetic_attributes=True) tid_molecules_list, failed_smi = list_matching_torsions( smi_file='smiles-to-keep.smi', forcefield=forcefield) pickle.dump(tid_molecules_list, open('tid_molecules_list.p', 'wb')) gen_pdf(tid_molecules_list, output_path='tid_molecules_list.pdf')
def _rdkit_parameteriser(cls, mol, **kwargs): from rdkit import Chem from openforcefield.utils.toolkits import RDKitToolkitWrapper, ToolkitRegistry """ Creates a parameterised system from rdkit molecule Parameters ---------- mol : rdkit.Chem.Mol """ try: forcefield = ForceField('test_forcefields/smirnoff99Frosst.offxml') molecule = Molecule.from_rdkit( mol, allow_undefined_stereo=cls.allow_undefined_stereo) if hasattr(cls, "_ddec_charger"): molecule.partial_charges = unit.Quantity( np.array(cls._ddec_charger(mol, cls.rf)), unit.elementary_charge) else: from openforcefield.utils.toolkits import AmberToolsToolkitWrapper molecule.compute_partial_charges_am1bcc( toolkit_registry=AmberToolsToolkitWrapper()) topology = Topology.from_molecules(molecule) openmm_system = forcefield.create_openmm_system( topology, charge_from_molecules=[molecule]) ligand_pmd = parmed.openmm.topsystem.load_topology( topology.to_openmm(), openmm_system, molecule._conformers[0]) except Exception as e: raise ValueError("Parameterisation Failed : {}".format(e)) #TODO ligand_pmd.title = cls.smiles for i in ligand_pmd.residues: i.name = 'LIG' tmp_dir = tempfile.mkdtemp() # We need all molecules as both pdb files (as packmol input) # and mdtraj.Trajectory for restoring bonds later. pdb_filename = tempfile.mktemp(suffix=".pdb", dir=tmp_dir) Chem.MolToPDBFile(mol, pdb_filename) cls.pdb_filename = pdb_filename cls.ligand_pmd = ligand_pmd
def getForceField(*ffpaths): hasher = hashlib.md5() for path in ffpaths: with open(path, 'rb') as f: hasher.update(f.read()) cache_key = hasher.hexdigest() if cache_key not in SMIRNOFF_FORCE_FIELD_CACHE: SMIRNOFF_FORCE_FIELD_CACHE[cache_key] = ForceField(*ffpaths, allow_cosmetic_attributes=True) return SMIRNOFF_FORCE_FIELD_CACHE[cache_key]
mol_filename = 'mol1.mol2' # Define a few simulation parameters time_step = 2*unit.femtoseconds # simulation timestep temperature = 300*unit.kelvin # simulation temperature friction = 1/unit.picosecond # collision rate num_steps = 1000000 # number of steps to run trj_freq = 1000 # number of steps per written trajectory frame data_freq = 1000 # number of steps per written simulation statistics # Load molecule and create pdb object pdb = PDBFile(pdb_filename) # Load a SMIRNOFF forcefield #forcefield = ForceField(get_data_filename('forcefield/Frosst_AlkEthOH_parmAtFrosst.offxml')) forcefield = ForceField(get_data_filename('forcefield/smirnoff99Frosst.offxml')) # Load molecule using OpenEye tools mol = oechem.OEGraphMol() ifs = oechem.oemolistream(mol_filename) # LPW: I don't understand the meaning of these lines. # flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_MOL2_Default | oechem.OEIFlavor_MOL2_Forcefield # ifs.SetFlavor( oechem.OEFormat_MOL2, flavor) oechem.OEReadMolecule(ifs, mol) oechem.OETriposAtomNames(mol) pdbatoms = list(pdb.topology.atoms()) labels = forcefield.labelMolecules([mol])[0] for key, val in labels.items(): print(key)