def test_debug_ffxml(self): """Test that debug ffxml file is created when requested""" with tempfile.TemporaryDirectory() as tmpdirname: debug_ffxml_filename = os.path.join(tmpdirname, 'molecule.ffxml') cache = os.path.join(tmpdirname, 'db.json') # Create a generator that only knows about one molecule molecule = self.molecules[0] generator = self.TEMPLATE_GENERATOR(molecules=molecule, cache=cache) # Create a ForceField from simtk.openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Ensure no file is created from simtk.openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert not os.path.exists(debug_ffxml_filename) # Enable debug file output creation forcefield = ForceField() forcefield.registerTemplateGenerator(generator.generator) generator.debug_ffxml_filename = debug_ffxml_filename # Ensure that an ffxml file is created system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert os.path.exists(debug_ffxml_filename) # Ensure we can use that file to create a new force field forcefield_from_ffxml = ForceField() if hasattr(generator, 'gaff_xml_filename'): forcefield_from_ffxml.loadFile(generator.gaff_xml_filename) forcefield_from_ffxml.loadFile(debug_ffxml_filename) system2 = forcefield_from_ffxml.createSystem(openmm_topology, nonbondedMethod=NoCutoff) # TODO: Test that systems are equivalent assert system.getNumParticles() == system2.getNumParticles()
def _parse_force_field(self, *args): if args[0] == 'TraPPE-UA': self.forceField = ForceField(self.TRAPPEUA_FF_PATH) elif args[0] == 'OPLS-AA': self.forceField = ForceField(self.OPLS_AA_PATH) else: raise ValueError("Invalid force field.") self.forceField_str = args[0]
def test_cache(self): """Test template generator cache capability""" from simtk.openmm.app import ForceField, NoCutoff with tempfile.TemporaryDirectory() as tmpdirname: # Create a generator that also has a database cache cache = os.path.join(tmpdirname, 'db.json') generator = self.TEMPLATE_GENERATOR(molecules=self.molecules, cache=cache) # Create a ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize the molecules for molecule in self.molecules: openmm_topology = molecule.to_topology().to_openmm() forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) # Check database contents def check_cache(generator, n_expected): """ Check database contains number of expected records Parameters ---------- generator : SmallMoleculeTemplateGenerator The generator whose cache should be examined n_expected : int Number of expected records """ from tinydb import TinyDB db = TinyDB(generator._cache) table = db.table(generator._database_table_name) db_entries = table.all() db.close() n_entries = len(db_entries) assert (n_entries == n_expected), \ "Expected {} entries but database has {}\n db contents: {}".format(n_expected, n_entries, db_entries) check_cache(generator, len(self.molecules)) # Clean up, forcing closure of database del forcefield, generator # Create a generator that also uses the database cache but has no molecules print('Creating new generator with just cache...') generator = self.TEMPLATE_GENERATOR(cache=cache) # Check database still contains the molecules we expect check_cache(generator, len(self.molecules)) # Create a ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize the molecules; this should succeed for molecule in self.molecules: openmm_topology = molecule.to_topology().to_openmm() forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff)
def _prep_sim(self, coords, external_forces=[]): try: from simtk.openmm import Platform, LangevinIntegrator, Vec3 from simtk.openmm.app import Modeller, ForceField, \ CutoffNonPeriodic, PME, Simulation, HBonds from simtk.unit import angstrom, nanometers, picosecond, \ kelvin, Quantity, molar except ImportError: raise ImportError( 'Please install PDBFixer and OpenMM in order to use ClustENM.') positions = Quantity([Vec3(*xyz) for xyz in coords], angstrom) modeller = Modeller(self._topology, positions) if self._sol == 'imp': forcefield = ForceField(*self._force_field) system = forcefield.createSystem(modeller.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds) if self._sol == 'exp': forcefield = ForceField(*self._force_field) modeller.addSolvent(forcefield, padding=self._padding * nanometers, ionicStrength=self._ionicStrength * molar) system = forcefield.createSystem(modeller.topology, nonbondedMethod=PME, nonbondedCutoff=1.0 * nanometers, constraints=HBonds) for force in external_forces: system.addForce(force) integrator = LangevinIntegrator(self._temp * kelvin, 1 / picosecond, 0.002 * picosecond) # precision could be mixed, but single is okay. platform = self._platform if self._platform is None else Platform.getPlatformByName( self._platform) properties = None if self._platform is None: properties = {'Precision': 'single'} elif self._platform in ['CUDA', 'OpenCL']: properties = {'Precision': 'single'} simulation = Simulation(modeller.topology, system, integrator, platform, properties) simulation.context.setPositions(modeller.positions) return simulation
def test_gaffResidueTemplateGenerator(): """ Test the GAFF residue template generator. """ # # Test where we generate parameters for only a ligand. # # Load the PDB file. from simtk.openmm.app import PDBFile pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb") pdb = PDBFile(pdb_filename) # Create a ForceField object. gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml") forcefield = ForceField(gaff_xml_filename) # Add the residue template generator. from openmoltools.forcefield_generators import gaffTemplateGenerator forcefield.registerTemplateGenerator(gaffTemplateGenerator) # Parameterize system. system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff) # Check potential is finite. check_potential_is_finite(system, pdb.positions) # Check energy matches prmtop route. check_energy_components_vs_prmtop( prmtop=utils.get_data_filename('chemicals/imatinib/imatinib.prmtop'), inpcrd=utils.get_data_filename('chemicals/imatinib/imatinib.inpcrd'), system=system) # # Test where we generate parameters for only a ligand in a protein. # # Load the PDB file. from simtk.openmm.app import PDBFile pdb_filename = utils.get_data_filename( "chemicals/proteins/T4-lysozyme-L99A-p-xylene-implicit.pdb") pdb = PDBFile(pdb_filename) # Create a ForceField object. gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml") forcefield = ForceField('amber99sb.xml', gaff_xml_filename) # Add the residue template generator. from openmoltools.forcefield_generators import gaffTemplateGenerator forcefield.registerTemplateGenerator(gaffTemplateGenerator) # Parameterize system. system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff) # Check potential is finite. check_potential_is_finite(system, pdb.positions)
def test_charge_from_molecules(self): """Test that user-specified partial charges are used if requested""" # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField from simtk.openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule using user-provided charges produces expected charges import numpy as np from simtk import unit molecule = self.molecules[0] charges = np.random.random([molecule.n_particles]) charges += (molecule.total_charge - charges.sum()) / molecule.n_particles molecule.partial_charges = unit.Quantity(charges, unit.elementary_charge) assert not np.all(molecule.partial_charges / unit.elementary_charge == 0) # Add the molecule generator.add_molecules(molecule) # Create the System from simtk.openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert self.charges_are_equal(system, molecule)
def test_charge(self): """Test that charges are nonzero after charging if the molecule does not contain user charges""" # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField from simtk.openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule using user-provided charges produces expected charges import numpy as np from simtk import unit molecule = self.molecules[0] # Ensure partial charges are initially zero assert np.all(molecule.partial_charges / unit.elementary_charge == 0) # Add the molecule generator.add_molecules(molecule) # Create the System from simtk.openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) # Ensure charges are no longer zero assert not np.all( self.charges_from_system(system) == 0), "System has zero charges despite molecule not being charged"
def __init__(self, forcefields_to_use, forcefield_kwargs=None, use_gaff=True): self._forcefield_xmls = forcefields_to_use self._forcefield_kwargs = forcefield_kwargs if forcefield_kwargs is not None else {} from simtk.openmm.app import ForceField self._forcefield = ForceField(*self._forcefield_xmls) if use_gaff: self._forcefield.registerTemplateGenerator(gaffTemplateGenerator)
def test_membrane_modeller(): """Test the addition of hydrogens to a solvated DPPC molecule""" # pdb file corresponding to a solvated lipid molecule pdb = PDBFile(os.path.join(os.path.dirname(__file__), '../data/dppc/solvated-dppc.pdb')) modeller = MembraneModeller(pdb.topology,pdb.positions) modeller.modify_topology() forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml') modeller.addHydrogens(forcefield=forcefield) system = forcefield.createSystem(modeller.topology, nonbondedMethod=app.PME, rigidWater=True, nonbondedCutoff=1*unit.nanometer) integrator = mm.VerletIntegrator(0.5*unit.femtoseconds) platform = mm.Platform.getPlatformByName('Reference') simulation = app.Simulation(modeller.topology, system, integrator, platform) simulation.context.setPositions(modeller.positions) simulation.context.setVelocitiesToTemperature(300*unit.kelvin) # Minimize the system after adding hydrogens simulation.minimizeEnergy(maxIterations=200) # Run a few MD steps to check the system has no overlaps simulation.step(1000) state = simulation.context.getState(getEnergy=True) pe = state.getPotentialEnergy()._value assert pe < 0.0
def test_porin_membrane_system(): """Test the addition of a ligand to a solvated porin""" # pdb file corresponding to a solvated porin pdb = PDBFile( os.path.join(os.path.dirname(__file__), '../data/porin/solvated-porin.pdb')) modeller = app.Modeller(pdb.topology, pdb.positions) forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml') platform = mm.Platform.getPlatformByName('CPU') modeller.addHydrogens(forcefield=forcefield) # rigidWater False is required for ParMed to access water paramters system_md = forcefield.createSystem(modeller.topology, nonbondedMethod=app.PME, rigidWater=False, nonbondedCutoff=1 * unit.nanometer) ligand_system = PorinMembraneSystem('comp7', system_md, modeller.topology, modeller.positions, platform, tolerance=1 * unit.kilojoule / unit.mole, max_iterations=200) integrator = mm.LangevinIntegrator(300 * unit.kelvin, 1.0 / unit.picoseconds, 2 * unit.femtosecond) simulation = app.Simulation(ligand_system.structure.topology, ligand_system.system, integrator, platform) simulation.context.setPositions(ligand_system.structure.positions) state = simulation.context.getState(getEnergy=True) pe = state.getPotentialEnergy()._value assert pe < 0.0
def test_generate_ffxml_from_molecules(): """ Test generation of single ffxml file from a list of molecules """ # Create a test set of molecules. molecules = [createOEMolFromIUPAC(name) for name in IUPAC_molecule_names] # Create an ffxml file. from openmoltools.forcefield_generators import generateForceFieldFromMolecules ffxml = generateForceFieldFromMolecules(molecules) # Create a ForceField. gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml") forcefield = ForceField(gaff_xml_filename) try: forcefield.loadFile(StringIO(ffxml)) except Exception as e: msg = str(e) msg += "ffxml contents:\n" for (index, line) in enumerate(ffxml.split('\n')): msg += 'line %8d : %s\n' % (index, line) raise Exception(msg) # Parameterize the molecules. from openmoltools.forcefield_generators import generateTopologyFromOEMol for molecule in molecules: # Create topology from molecule. topology = generateTopologyFromOEMol(molecule) # Create system with forcefield. system = forcefield.createSystem(topology) # Check potential is finite. positions = extractPositionsFromOEMOL(molecule) check_potential_is_finite(system, positions)
def test_parameterize(self): """Test parameterizing molecules with template generator for all supported force fields""" # Test all supported small molecule force fields for small_molecule_forcefield in self.TEMPLATE_GENERATOR.INSTALLED_FORCEFIELDS: print(f'Testing {small_molecule_forcefield}') # Create a generator that knows about a few molecules # TODO: Should the generator also load the appropriate force field files into the ForceField object? generator = self.TEMPLATE_GENERATOR(molecules=self.molecules, forcefield=small_molecule_forcefield) # Check that we have loaded the right force field assert generator.forcefield == small_molecule_forcefield # Create a ForceField with the appropriate small molecule force field from simtk.openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize some molecules from simtk.openmm.app import NoCutoff from openmmforcefields.utils import Timer for molecule in self.molecules: openmm_topology = molecule.to_topology().to_openmm() with Timer() as t1: system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert system.getNumParticles() == molecule.n_atoms # Molecule should now be cached with Timer() as t2: system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert system.getNumParticles() == molecule.n_atoms assert (t2.interval() < t1.interval())
def test_membraneModeller(): # pdb file containing a solvated single lipid molecule pdb = PDBFile('solvated-lipid.pdb') modeller = Modeller(pdb.topology,pdb.positions) modeller.modifyTopology() forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml') modeller.addHydrogens(forcefield=forcefield) system = forcefield.createSystem(modeller.topology, nonbondedMethod=app.PME, rigidWater=True, nonbondedCutoff=1*unit.nanometer) integrator = mm.VerletIntegrator(0.5*unit.femtoseconds) platform = mm.Platform.getPlatformByName('Reference') simulation = app.Simulation(modeller.topology, system, integrator, platform) simulation.context.setPositions(modeller.positions) simulation.context.setVelocitiesToTemperature(300*unit.kelvin) # Minimize the system after adding hydrogens tolerance = 0.1*unit.kilojoules_per_mole/unit.angstroms simulation.minimizeEnergy(tolerance=tolerance,maxIterations=200) simulation.reporters.append(app.StateDataReporter('relax-hydrogens.log', 1000, step=True, potentialEnergy=True)) simulation.step(1000)
def imatinib_timing(): print("Loading imatinib...") # Load the PDB file. from simtk.openmm.app import PDBFile pdb_filename = utils.get_data_filename("chemicals/imatinib/imatinib.pdb") pdb = PDBFile(pdb_filename) # Create a ForceField object. gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml") forcefield = ForceField(gaff_xml_filename) # Add the residue template generator. from openmoltools.forcefield_generators import gaffTemplateGenerator forcefield.registerTemplateGenerator(gaffTemplateGenerator) # Parameterize system. system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff) integrator = openmm.LangevinIntegrator(300 * unit.kelvin, 5.0 / unit.picoseconds, 1.0 * unit.femtoseconds) # Create Context context = openmm.Context(system, integrator) context.setPositions(pdb.positions) integrator.step(100) import time nsteps = 10000000 initial_time = time.time() integrator.step(nsteps) state = context.getState().getPeriodicBoxVectors() # force dynamics final_time = time.time() elapsed_time = final_time / initial_time time_per_step = elapsed_time / float(nsteps) print('time per force evaluation is %.3f us' % (time_per_step * 1e6))
def test_add_solvent(self): """Test using simtk.opnmm.app.Modeller to add solvent to a small molecule parameterized by template generator""" # Select a molecule to add solvent around from simtk.openmm.app import NoCutoff, Modeller from simtk import unit molecule = self.molecules[0] openmm_topology = molecule.to_topology().to_openmm() openmm_positions = molecule.conformers[0] # Try adding solvent without residue template generator; this will fail from simtk.openmm.app import ForceField forcefield = ForceField('tip3p.xml') # Add solvent to a system containing a small molecule modeller = Modeller(openmm_topology, openmm_positions) try: modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms) except ValueError as e: pass # Create a generator that knows about a few molecules generator = self.TEMPLATE_GENERATOR(molecules=self.molecules) # Add to the forcefield object forcefield.registerTemplateGenerator(generator.generator) # Add solvent to a system containing a small molecule # This should succeed modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms)
def test_generateResidueTemplate(): """ Test GAFF residue template generation from OEMol molecules. """ from openeye import oechem, oeiupac from pkg_resources import resource_filename gaff_xml_filename = utils.get_data_filename("parameters/gaff.xml") # Test independent ForceField instances. for molecule_name in IUPAC_molecule_names: mol = createOEMolFromIUPAC(molecule_name) # Generate an ffxml residue template. from openmoltools.forcefield_generators import generateResidueTemplate [template, ffxml] = generateResidueTemplate(mol) # Create a ForceField object. forcefield = ForceField(gaff_xml_filename) # Add the additional parameters and template to the forcefield. forcefield.registerResidueTemplate(template) forcefield.loadFile(StringIO(ffxml)) # Create a Topology from the molecule. from openmoltools.forcefield_generators import generateTopologyFromOEMol topology = generateTopologyFromOEMol(mol) # Parameterize system. system = forcefield.createSystem(topology, nonbondedMethod=NoCutoff) # Check potential is finite. positions = extractPositionsFromOEMOL(mol) check_potential_is_finite(system, positions) # Test adding multiple molecules to a single ForceField instance. forcefield = ForceField(gaff_xml_filename) for molecule_name in IUPAC_molecule_names: mol = createOEMolFromIUPAC(molecule_name) # Generate an ffxml residue template. from openmoltools.forcefield_generators import generateResidueTemplate [template, ffxml] = generateResidueTemplate(mol) # Add the additional parameters and template to the forcefield. forcefield.registerResidueTemplate(template) forcefield.loadFile(StringIO(ffxml)) # Create a Topology from the molecule. from openmoltools.forcefield_generators import generateTopologyFromOEMol topology = generateTopologyFromOEMol(mol) # Parameterize system. system = forcefield.createSystem(topology, nonbondedMethod=NoCutoff) # Check potential is finite. positions = extractPositionsFromOEMOL(mol) check_potential_is_finite(system, positions)
def test_jacs_ligands(self): """Use template generator to parameterize the Schrodinger JACS set of ligands""" from simtk.openmm.app import ForceField, NoCutoff jacs_systems = { #'bace' : { 'prefix' : 'Bace' }, #'cdk2' : { 'prefix' : 'CDK2' }, 'jnk1' : { 'prefix' : 'Jnk1' }, 'mcl1' : { 'prefix' : 'MCL1' }, #'p38' : { 'prefix' : 'p38' }, 'ptp1b' : { 'prefix' : 'PTP1B' }, 'thrombin' : { 'prefix' : 'Thrombin' }, #'tyk2' : { 'prefix' : 'Tyk2' }, } for system_name in jacs_systems: prefix = jacs_systems[system_name]['prefix'] # Load molecules ligand_sdf_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_ligands.sdf')) print(f'Reading molecules from {ligand_sdf_filename} ...') from openforcefield.topology import Molecule molecules = Molecule.from_file(ligand_sdf_filename, allow_undefined_stereo=True) # Ensure this is a list try: nmolecules = len(molecules) except TypeError: molecules = [molecules] print(f'Read {len(molecules)} molecules from {ligand_sdf_filename}') #molecules = self.filter_molecules(molecules) MAX_MOLECULES = len(molecules) if 'TRAVIS' in os.environ: MAX_MOLECULES = 3 molecules = molecules[:MAX_MOLECULES] print(f'{len(molecules)} molecules remain after filtering') # Create template generator with local cache cache = os.path.join(get_data_filename(os.path.join('perses_jacs_systems', system_name)), 'cache.json') generator = self.TEMPLATE_GENERATOR(molecules=molecules, cache=cache) # Create a ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize all molecules print(f'Caching all molecules for {system_name} at {cache} ...') n_success = 0 n_failure = 0 for molecule in molecules: openmm_topology = molecule.to_topology().to_openmm() try: forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) n_success += 1 except Exception as e: n_failure += 1 print(e) print(f'{n_failure}/{n_success+n_failure} ligands failed to parameterize for {system_name}')
def __init__(self, system_options): super(DodecaneAcrylateTopologyOptions, self).__init__(system_options) self.forceField_str = "TraPPE-UA" self.forceField = ForceField(self.TRAPPEUA_FF_PATH) self.numDodecane = 0 self.numSqualane = 0 self.dodecaneInstructions = None self.box_vectors = None self.chains = [] self.branched_chains = [] self.id_to_sequence = {}
def createSystemFromIUPAC(iupac_name): """ Create an openmm system out of an oemol Parameters ---------- iupac_name : str IUPAC name Returns ------- molecule : openeye.OEMol OEMol molecule system : openmm.System object OpenMM system positions : [n,3] np.array of floats Positions topology : openmm.app.Topology object Topology """ from perses.utils.data import get_data_filename from perses.utils.openeye import extractPositionsFromOEMol # Create OEMol molecule = iupac_to_oemol(iupac_name) # Generate a topology. from openmoltools.forcefield_generators import generateTopologyFromOEMol topology = generateTopologyFromOEMol(molecule) # Initialize a forcefield with GAFF. # TODO: Fix path for `gaff.xml` since it is not yet distributed with OpenMM from simtk.openmm.app import ForceField gaff_xml_filename = get_data_filename('data/gaff.xml') forcefield = ForceField(gaff_xml_filename) # Generate template and parameters. from openmoltools.forcefield_generators import generateResidueTemplate [template, ffxml] = generateResidueTemplate(molecule) # Register the template. forcefield.registerResidueTemplate(template) # Add the parameters. forcefield.loadFile(StringIO(ffxml)) # Create the system. system = forcefield.createSystem(topology, removeCMMotion=False) # Extract positions positions = extractPositionsFromOEMol(molecule) return (molecule, system, positions, topology)
def add_hydrogens_by_openmm(self): from simtk.openmm.app import ForceField, Modeller, PDBFile from pdbfixer import PDBFixer fixer = PDBFixer(self.name) field = ForceField('amber99sb.xml', 'tip3p.xml') fixer.findMissingResidues() fixer.findMissingAtoms() fixer.addMissingAtoms() fixer.addMissingHydrogens(7.0) modeller = Modeller(fixer.topology, fixer.positions) modeller.addHydrogens(forcefield=field) modeller.deleteWater() PDBFile.writeModel(modeller.topology, modeller.positions, open(self.shotname+'_h.pdb', 'w'))
def test_xtc_reporter_append(tmpdir, get_fn): pdb = PDBFile(get_fn('native.pdb')) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') # NO PERIODIC BOUNDARY CONDITIONS system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) xtcfile = os.path.join(tmpdir, 'traj.xtc') xtcfile_cp = os.path.join(tmpdir, 'traj_cp.xtc') checkpoint = os.path.join(tmpdir, 'checkpoint.chk') reporter = XTCReporter(xtcfile, 2) simulation.reporters.append(reporter) simulation.reporters.append(CheckpointReporter(checkpoint, 10)) simulation.step(10) reporter.close() shutil.copyfile(xtcfile, xtcfile_cp) system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.loadCheckpoint(checkpoint) reporter = XTCReporter(xtcfile, 2, append=True) simulation.reporters.append(reporter) simulation.step(10) reporter.close() xtc_traj = md.load(xtcfile, top=get_fn('native.pdb')) xtc_traj_cp = md.load(xtcfile_cp, top=get_fn('native.pdb')) eq(xtc_traj.xyz[:5], xtc_traj_cp.xyz) eq(xtc_traj.n_frames, 10) eq(xtc_traj_cp.n_frames, 5) eq(xtc_traj.time[:5], xtc_traj_cp.time)
def from_pickle(cls, path, positions=None, forcefield=None, **kwargs): if positions is None: raise ValueError( 'Pickled topology files require initial positions.') if forcefield is None: raise ValueError( 'Pickled topology files require XML/FRCMOD forcefields.') topology = cls._pickle_load(path) forcefield = ForceField(*list(process_forcefield(*forcefield))) return cls(master=forcefield, topology=topology, positions=positions, path=path, **kwargs)
def calculate_fragment_energetics(frag_no=1): """ * Create an OpenMM system with a fragment. * Calculate the energy of the system and print. :param frag_no: The number of the fragment being analysed (used to access files). """ os.chdir(f'group2/frag{frag_no}') # Necessary due to size of calculation sys.setrecursionlimit(15000) pdb = PDBFile(f'QUBE_pro_frag{frag_no}.pdb') forcefield = ForceField(f'QUBE_pro_frag{frag_no}_plus.xml') system = forcefield.createSystem( pdb.topology, nonbondedMethod=NoCutoff, ) system = apply_opls_combo(system) with open(f'QUBE_pro_frag{frag_no}_out.xml', 'w') as outfile: serialized_system = XmlSerializer.serialize(system) outfile.write(serialized_system) # Create the integrator to do Langevin dynamics integrator = LangevinIntegrator( 298.15 * unit.kelvin, # Temperature of heat bath 1.0 / unit.picoseconds, # Friction coefficient 2.0 * unit.femtoseconds, # Time step ) platform = Platform.getPlatformByName('CPU') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) print('energy from openmm library') print(simulation.context.getState(getEnergy=True).getPotentialEnergy()) structure = parmed.load_file(f'QUBE_pro_frag{frag_no}.pdb') energy_comps = parmed.openmm.energy_decomposition_system(structure, system) total_energy = 0.0 for comp in energy_comps: total_energy += comp[1] print(*comp) print(f'Total energy {total_energy: 6.6f}')
def test_multiple_registration(self): """Test registering the template generator with multiple force fields""" generator = self.TEMPLATE_GENERATOR(molecules=self.molecules) from simtk.openmm.app import ForceField NUM_FORCEFIELDS = 2 # number of force fields to test forcefields = list() for index in range(NUM_FORCEFIELDS): forcefield = ForceField() forcefield.registerTemplateGenerator(generator.generator) forcefields.append(forcefield) # Parameterize a molecule in each force field instance molecule = self.molecules[0] openmm_topology = molecule.to_topology().to_openmm() from simtk.openmm.app import NoCutoff for forcefield in forcefields: system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert system.getNumParticles() == molecule.n_atoms
def setup(args: ListOfArgs) -> Tuple[PDBFile, int, Simulation]: print("Initialization...") if args.SIM_RANDOM_SEED == 0: random_seed = np.random.randint(2147483647) else: random_seed = args.SIM_RANDOM_SEED print(f" Loading initial structure: {args.INITIAL_STRUCTURE_PATH}") pdb = PDBFile(args.INITIAL_STRUCTURE_PATH) print(f" Loading forcefield file: {args.FORCEFIELD_PATH}") forcefield = ForceField(args.FORCEFIELD_PATH) print(" Building system...") system = forcefield.createSystem(pdb.topology) add_forces_to_system(system, args) integrator = get_integrator(random_seed, args) print(" Setting up simulation...") simulation = Simulation(pdb.topology, system, integrator) simulation.context.setPositions(pdb.positions) return pdb, random_seed, simulation
def test_add_molecules(self): """Test that molecules can be added to template generator after its creation""" # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField from simtk.openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule fails molecule = self.molecules[0] from simtk.openmm.app import NoCutoff try: # This should fail with an exception openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) except ValueError as e: # Exception 'No template found...' is expected assert str(e).startswith('No template found') # Now add the molecule to the generator and ensure parameterization passes generator.add_molecules(molecule) openmm_topology = molecule.to_topology().to_openmm() try: system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) except Exception as e: print(forcefield._atomTypes.keys()) from simtk.openmm.app import PDBFile PDBFile.writeFile(openmm_topology, molecule.conformers[0]) raise e assert system.getNumParticles() == molecule.n_atoms # Add multiple molecules, including repeats generator.add_molecules(self.molecules) # Ensure all molecules can be parameterized for molecule in self.molecules: openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert system.getNumParticles() == molecule.n_atoms
def check_hydrogens(molecule, ID): # Check that Hydrogens are in structure if len(molecule.top.select("name == H")) == 0: # If absent, then add Hydrogens using the Amber99sb force-field try: from simtk.openmm.app import PDBFile, Modeller, ForceField pdb = PDBFile(ID + ".pdb") modeller = Modeller(pdb.topology, pdb.positions) forcefield = ForceField('amber99sb.xml', 'tip3p.xml') modeller.addHydrogens(forcefield) PDBFile.writeFile(modeller.topology, modeller.positions, open(ID + ".pdb", 'w')) molecule = md.load(ID + ".pdb").remove_solvent() except: warnings.warn( """PDB topology missing Hydrogens. Either manually add or install OpenMM through SIMTK to automatically correct.""") pass return molecule
def from_pdb(cls, path, forcefield=None, loader=PDBFile, strict=True, **kwargs): """ Loads topology, positions and, potentially, velocities and vectors, from a PDB or PDBx file Parameters ---------- path : str Path to PDB/PDBx file forcefields : list of str Paths to FFXML and/or FRCMOD forcefields. REQUIRED. Returns ------- pdb : SystemHandler SystemHandler with topology, positions, and, potentially, velocities and box vectors. Forcefields are embedded in the `master` attribute. """ pdb = loader(path) box = kwargs.pop('box', pdb.topology.getPeriodicBoxVectors()) positions = kwargs.pop('positions', pdb.positions) velocities = kwargs.pop('velocities', getattr(pdb, 'velocities', None)) if strict and not forcefield: from .md import FORCEFIELDS as forcefield logger.info( '! Forcefields for PDB not specified. Using default: %s', ', '.join(forcefield)) pdb.forcefield = ForceField(*list(process_forcefield(*forcefield))) return cls(master=pdb.forcefield, topology=pdb.topology, positions=positions, velocities=velocities, box=box, path=path, **kwargs)
def __init__(self, pdb_path, offset_size=2): # OpenMM init self.pdb_path = pdb_path self.pdb = PDBFile(self.pdb_path) self.forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml') self.modeller = Modeller(self.pdb.topology, self.pdb.positions) # Remove any water that might be present in the PDB file self.modeller.deleteWater() # Add any hydrogens not present self.modeller.addHydrogens(self.forcefield) self.system = self.forcefield.createSystem(self.modeller.topology, nonbondedMethod=PME, nonbondedCutoff=1 * u.nanometer, constraints=HBonds) self.integrator = LangevinIntegrator(300 * u.kelvin, 1 / u.picosecond, 0.002 * u.picoseconds) self.simulation = Simulation(self.modeller.topology, self.system, self.integrator) self.pdb_positions = self.modeller.getPositions() # Initialize bond dictionary and positions for chemcoord self.cc_bonds = {} self.offset_size = offset_size self._init_pdb_bonds() self.set_cc_positions(self.pdb_positions) # Perform initial minimization, which updates self.pdb_positions min_energy, min_positions = self.run_simulation() # Reset the positions after the minimization self.set_cc_positions(self.pdb_positions) self.torsion_indices = self._get_torsion_indices() self.starting_positions = min_positions self.starting_torsions = np.array([ self.zmat.loc[self.torsion_indices[:, 0], 'dihedral'], self.zmat.loc[self.torsion_indices[:, 1], 'dihedral'] ]).T self.seed_offsets()
def test_jacs_complexes(self): """Use template generator to parameterize the Schrodinger JACS set of complexes""" # TODO: Uncomment working systems when we have cleaned up the input files jacs_systems = { #'bace' : { 'prefix' : 'Bace' }, #'cdk2' : { 'prefix' : 'CDK2' }, #'jnk1' : { 'prefix' : 'Jnk1' }, 'mcl1' : { 'prefix' : 'MCL1' }, #'p38' : { 'prefix' : 'p38' }, #'ptp1b' : { 'prefix' : 'PTP1B' }, #'thrombin' : { 'prefix' : 'Thrombin' }, #'tyk2' : { 'prefix' : 'Tyk2' }, } for system_name in jacs_systems: prefix = jacs_systems[system_name]['prefix'] # Read molecules ligand_sdf_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_ligands.sdf')) print(f'Reading molecules from {ligand_sdf_filename} ...') from openforcefield.topology import Molecule molecules = Molecule.from_file(ligand_sdf_filename, allow_undefined_stereo=True) try: nmolecules = len(molecules) except TypeError: molecules = [molecules] print(f'Read {len(molecules)} molecules from {ligand_sdf_filename}') # Read ParmEd Structures import parmed from simtk import unit protein_pdb_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_protein.pdb')) from simtk.openmm.app import PDBFile print(f'Reading protein from {protein_pdb_filename} ...') #protein_structure = parmed.load_file(protein_pdb_filename) # NOTE: This mis-interprets distorted geometry and sequentially-numbered residues that span chain breaks pdbfile = PDBFile(protein_pdb_filename) protein_structure = parmed.openmm.load_topology(pdbfile.topology, xyz=pdbfile.positions.value_in_unit(unit.angstroms)) ligand_structures = parmed.load_file(ligand_sdf_filename) try: nmolecules = len(ligand_structures) except TypeError: ligand_structures = [ligand_structures] assert len(ligand_structures) == len(molecules) # Filter molecules if 'TRAVIS' in os.environ: MAX_MOLECULES = 3 else: MAX_MOLECULES = 6 molecules = molecules[:MAX_MOLECULES] ligand_structures = ligand_structures[:MAX_MOLECULES] print(f'{len(molecules)} molecules remain after filtering') # Create complexes complex_structures = [ (protein_structure + ligand_structure) for ligand_structure in ligand_structures ] # Create template generator with local cache cache = os.path.join(get_data_filename(os.path.join('perses_jacs_systems', system_name)), 'cache.json') generator = self.TEMPLATE_GENERATOR(molecules=molecules, cache=cache) # Create a ForceField from simtk.openmm.app import ForceField forcefield = ForceField(*self.amber_forcefields) # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize all complexes print(f'Caching all molecules for {system_name} at {cache} ...') for ligand_index, complex_structure in enumerate(complex_structures): openmm_topology = complex_structure.topology molecule = molecules[ligand_index] # Delete hydrogens from terminal protein residues # TODO: Fix the input files so we don't need to do this from simtk.openmm import app modeller = app.Modeller(complex_structure.topology, complex_structure.positions) residues = [residue for residue in modeller.topology.residues() if residue.name != 'UNL'] termini_ids = [residues[0].id, residues[-1].id] #hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.name != 'UNL'] hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.id in termini_ids] modeller.delete(hs) from simtk.openmm.app import PDBFile modeller.addHydrogens(forcefield) # Parameterize protein:ligand complex in vacuum print(f' Parameterizing {system_name} : {molecule.to_smiles()} in vacuum...') from simtk.openmm.app import NoCutoff forcefield.createSystem(modeller.topology, nonbondedMethod=NoCutoff) # Parameterize protein:ligand complex in solvent print(f' Parameterizing {system_name} : {molecule.to_smiles()} in explicit solvent...') from simtk.openmm.app import PME modeller.addSolvent(forcefield, padding=0*unit.angstroms, ionicStrength=300*unit.millimolar) forcefield.createSystem(modeller.topology, nonbondedMethod=PME)