def energy_decomposition_system(structure, system, platform=None, nrg=u.kilocalories_per_mole): """ This function computes the energy contribution for all of the different force groups. Parameters ---------- structure : Structure The Structure with the coordinates for this system system : mm.System The OpenMM System object to get decomposed energies from platform : str The platform to use. Options are None (default), 'CPU', 'Reference', 'CUDA', and 'OpenCL'. None will pick default OpenMM platform for this installation and computer nrg : energy unit, optional The unit to convert all energies into. Default is kcal/mol Returns ------- energies : list of tuple Each entry is a tuple with the name of the force followed by its contribution """ import simtk.openmm as mm # First get all of the old force groups so we can restore them old_groups = [f.getForceGroup() for f in system.getForces()] old_recip_group = [] def _ene(context, grp): st = context.getState(getEnergy=True, groups=1 << grp) return (type(system.getForce(grp)).__name__, st.getPotentialEnergy().value_in_unit(nrg)) try: for i, f in enumerate(system.getForces()): if isinstance(f, mm.NonbondedForce): old_recip_group.append(f.getReciprocalSpaceForceGroup()) f.setReciprocalSpaceForceGroup(i) f.setForceGroup(i) if platform is None: con = mm.Context(system, mm.VerletIntegrator(0.001)) else: con = mm.Context(system, mm.VerletIntegrator(0.001), mm.Platform.getPlatformByName(platform)) con.setPositions(structure.positions) if structure.box is not None: con.setPeriodicBoxVectors(*structure.box_vectors) return list(map(lambda x: _ene(con, x), range(system.getNumForces()))) finally: idx = 0 for grp, force in zip(old_groups, system.getForces()): if isinstance(force, mm.NonbondedForce): force.setReciprocalSpaceForceGroup(old_recip_group[idx]) idx += 1 force.setForceGroup(grp)
def set_thermo(system, args): ''' Takes care of thermostat if needed ''' if args.temperature <= 0.0: logger.info("This is a constant energy, constant volume (NVE) run.") integrator = mm.VerletIntegrator(2.0 * u.femtoseconds) else: logger.info("This is a constant temperature run at %.2f K" % args.temperature) logger.info( "The stochastic thermostat collision frequency is %.2f ps^-1" % args.collision_rate) if args.integrator == "langevin": logger.info( "Creating a Langevin integrator with %.2f fs timestep." % args.timestep) integrator = mm.LangevinIntegrator( args.temperature * u.kelvin, args.collision_rate / u.picoseconds, args.timestep * u.femtosecond) elif args.integrator == "verlet": integrator = mm.VerletIntegrator(2.0 * u.femtoseconds) thermostat = mm.AndersenThermostat( args.temperature * u.kelvin, args.collision_rate / u.picosecond) system.addForce(thermostat) else: logger.warning("Unknown integrator, will crash now") add_barostat(system, args) return integrator
def test_round_trip(self): """ Test ParmEd -> OpenMM round trip with Gromacs system """ # Use DPPC to get RB-torsions tested. Also check that it initially fails # with the CustomNonbondedForce warnings.filterwarnings('ignore', category=GromacsWarning) top = load_file(os.path.join(get_fn('12.DPPC'), 'topol.top'), xyz=os.path.join(get_fn('12.DPPC'), 'conf.gro')) self.assertEqual(top.combining_rule, 'lorentz') system = top.createSystem() def bad_system(): return openmm.load_topology(top.topology, system).createSystem() warnings.filterwarnings('ignore', category=OpenMMWarning) self.assertTrue( openmm.load_topology(top.topology, system).unknown_functional) self.assertRaises(ParmedError, bad_system) for i in range(len(system.getForces())): if isinstance(system.getForce(i), mm.CustomNonbondedForce): system.removeForce(i) break system2 = openmm.load_topology(top.topology, system).createSystem() con1 = mm.Context(system, mm.VerletIntegrator(0.001), CPU) con2 = mm.Context(system2, mm.VerletIntegrator(0.001), CPU) con1.setPositions(top.positions) con2.setPositions(top.positions) ene1 = energy_decomposition(top, con1) ene2 = energy_decomposition(top, con2) self.assertAlmostEqual(ene1['bond'], ene2['bond']) self.assertAlmostEqual(ene1['angle'], ene2['angle']) self.assertAlmostEqual(ene1['dihedral'], ene2['dihedral']) self.assertAlmostEqual(ene1['improper'], ene2['improper']) self.assertAlmostEqual(ene1['rb_torsion'], ene2['rb_torsion']) self.assertAlmostEqual(ene1['nonbonded'], ene2['nonbonded'])
def test_mutate_quick(): """ Abbreviated version of test_mutate_all for travis. """ import perses.rjmc.topology_proposal as topology_proposal import perses.rjmc.geometry as geometry from perses.tests.utils import compute_potential_components from openmmtools import testsystems as ts geometry_engine = geometry.FFAllAngleGeometryEngine() aminos = ['ALA','VAL','GLY','PHE','PRO','TRP'] for aa in aminos: topology, positions = _get_capped_amino_acid(amino_acid=aa) modeller = app.Modeller(topology, positions) ff_filename = "amber99sbildn.xml" max_point_mutants = 1 ff = app.ForceField(ff_filename) system = ff.createSystem(modeller.topology) chain_id = '1' system_generator = topology_proposal.SystemGenerator([ff_filename]) pm_top_engine = topology_proposal.PointMutationEngine(modeller.topology, system_generator, chain_id, max_point_mutants=max_point_mutants) current_system = system current_topology = modeller.topology current_positions = modeller.positions minimize_integrator = openmm.VerletIntegrator(1.0*unit.femtosecond) platform = openmm.Platform.getPlatformByName("Reference") minimize_context = openmm.Context(current_system, minimize_integrator, platform) minimize_context.setPositions(current_positions) initial_state = minimize_context.getState(getEnergy=True) initial_potential = initial_state.getPotentialEnergy() openmm.LocalEnergyMinimizer.minimize(minimize_context) final_state = minimize_context.getState(getEnergy=True, getPositions=True) final_potential = final_state.getPotentialEnergy() current_positions = final_state.getPositions() print("Minimized initial structure from %s to %s" % (str(initial_potential), str(final_potential))) for k, proposed_amino in enumerate(aminos): pm_top_engine._allowed_mutations = [[('2',proposed_amino)]] pm_top_proposal = pm_top_engine.propose(current_system, current_topology) new_positions, logp = geometry_engine.propose(pm_top_proposal, current_positions, beta) new_system = pm_top_proposal.new_system if np.isnan(logp): raise Exception("NaN in the logp") integrator = openmm.VerletIntegrator(1*unit.femtoseconds) platform = openmm.Platform.getPlatformByName("Reference") context = openmm.Context(new_system, integrator, platform) context.setPositions(new_positions) state = context.getState(getEnergy=True) print(compute_potential_components(context)) potential = state.getPotentialEnergy() potential_without_units = potential / potential.unit print(str(potential)) if np.isnan(potential_without_units): raise Exception("Energy after proposal is NaN")
def testGB1Energy(self): # HCT (uses mbondi radii internally) """ Compare OpenMM and CHARMM GB (igb=1) energies """ parm = charmm_gas system = parm.createSystem(param22, implicitSolvent=app.HCT) integrator = mm.VerletIntegrator(1.0 * u.femtoseconds) sim = app.Simulation(parm.topology, system, integrator) sim.context.setPositions(charmm_gas_crds.positions) energies = decomposed_energy(sim.context, parm) self.assertAlmostEqual(energies['bond'], 1.3351, places=3) self.assertAlmostEqual(energies['angle'], 14.1158, places=3) self.assertAlmostEqual(energies['urey'], 0.3669, places=3) self.assertAlmostEqual(energies['dihedral'], 14.2773, places=3) self.assertAlmostEqual(energies['improper'], 0.3344, places=3) self.assertAlmostEqual(energies['cmap'], -0.5239, places=3) self.assertRelativeEqual(energies['nonbond'], -102.1598379, places=5) system = parm.createSystem(param22, implicitSolvent=app.HCT, implicitSolventSaltConc=1.0 * u.molar) integrator = mm.VerletIntegrator(1.0 * u.femtoseconds) sim = app.Simulation(parm.topology, system, integrator) sim.context.setPositions(charmm_gas_crds.positions) energies = decomposed_energy(sim.context, parm) self.assertAlmostEqual(energies['bond'], 1.3351, places=3) self.assertAlmostEqual(energies['angle'], 14.1158, places=3) self.assertAlmostEqual(energies['urey'], 0.3669, places=3) self.assertAlmostEqual(energies['dihedral'], 14.2773, places=3) self.assertAlmostEqual(energies['improper'], 0.3344, places=3) self.assertAlmostEqual(energies['cmap'], -0.5239, places=3) self.assertRelativeEqual(energies['nonbond'], -102.5012873, places=5)
def testAlchemicalFactory(reference_system, coordinates, alchemical_atoms, platform_name='OpenCL'): """ Compare energies of reference system and fully-interacting alchemically modified system. ARGUMENTS reference_system (simtk.openmm.System) - the reference System object to compare with coordinates - the coordinates to assess energetics for alchemical_atoms (list of int) - the list of ligand atoms to alchemically modify """ import simtk.unit as units import simtk.openmm as openmm import time # Create a factory to produce alchemical intermediates. print "Creating alchemical factory..." initial_time = time.time() factory = AbsoluteAlchemicalFactory(reference_system, alchemical_atoms=alchemical_atoms) final_time = time.time() elapsed_time = final_time - initial_time print "AbsoluteAlchemicalFactory initialization took %.3f s" % elapsed_time # Create an alchemically-perturbed state corresponding to nearly fully-interacting. # NOTE: We use a lambda slightly smaller than 1.0 because the AlchemicalFactory does not use Custom*Force softcore versions if lambda = 1.0 identically. lambda_value = 1.0 - 1.0e-6 alchemical_state = AlchemicalState(0.00, lambda_value, lambda_value, lambda_value) #platform_name = 'Reference' # DEBUG platform = openmm.Platform.getPlatformByName(platform_name) # Create the perturbed system. print "Creating alchemically-modified state..." initial_time = time.time() alchemical_system = factory.createPerturbedSystem(alchemical_state) final_time = time.time() elapsed_time = final_time - initial_time # Compare energies. timestep = 1.0 * units.femtosecond print "Computing reference energies..." reference_integrator = openmm.VerletIntegrator(timestep) reference_context = openmm.Context(reference_system, reference_integrator, platform) reference_context.setPositions(coordinates) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() print "Computing alchemical energies..." alchemical_integrator = openmm.VerletIntegrator(timestep) alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) alchemical_context.setPositions(coordinates) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() delta = alchemical_potential - reference_potential print "reference system : %24.8f kcal/mol" % (reference_potential / units.kilocalories_per_mole) print "alchemically modified : %24.8f kcal/mol" % (alchemical_potential / units.kilocalories_per_mole) print "ERROR : %24.8f kcal/mol" % ((alchemical_potential - reference_potential) / units.kilocalories_per_mole) print "elapsed alchemical time %.3f s" % elapsed_time return delta
def overlap_check(): """ BUGS TO REPORT: * Even if epsilon = 0, energy of two overlapping atoms is 'nan'. * Periodicity in 'nan' if dr = 0.1 even in nonperiodic system """ # Create a reference system. logger.info("Creating Lennard-Jones cluster system...") #[reference_system, positions] = testsystems.LennardJonesFluid() #receptor_atoms = [0] #ligand_atoms = [1] system_container = testsystems.LysozymeImplicit() (reference_system, positions) = system_container.system, system_container.positions receptor_atoms = range(0,2603) # T4 lysozyme L99A ligand_atoms = range(2603,2621) # p-xylene unit = positions.unit positions = units.Quantity(np.array(positions / unit), unit) factory = AbsoluteAlchemicalFactory(reference_system, ligand_atoms=ligand_atoms) alchemical_state = AlchemicalState(0.00, 0.00, 0.00, 1.0) # Create the perturbed system. logger.info("Creating alchemically-modified state...") alchemical_system = factory.createPerturbedSystem(alchemical_state) # Compare energies. timestep = 1.0 * units.femtosecond logger.info("Computing reference energies...") integrator = openmm.VerletIntegrator(timestep) context = openmm.Context(reference_system, integrator) context.setPositions(positions) state = context.getState(getEnergy=True) reference_potential = state.getPotentialEnergy() del state, context, integrator logger.info(reference_potential) logger.info("Computing alchemical energies...") integrator = openmm.VerletIntegrator(timestep) context = openmm.Context(alchemical_system, integrator) dr = 0.1 * units.angstroms # TODO: Why does 0.1 cause periodic 'nan's? a = receptor_atoms[-1] b = ligand_atoms[-1] delta = positions[a,:] - positions[b,:] for k in range(3): positions[ligand_atoms,k] += delta[k] for i in range(30): r = dr * i positions[ligand_atoms,0] += dr context.setPositions(positions) state = context.getState(getEnergy=True) alchemical_potential = state.getPotentialEnergy() logger.info("%8.3f A : %f " % (r / units.angstroms, alchemical_potential / units.kilocalories_per_mole)) del state, context, integrator return
def compareSystemEnergies(positions, systems, descriptions, platform="CPU", precision=None): # Compare energies. timestep = 1.0 * units.femtosecond if platform: platform_name = platform.getName() if precision: if platform_name == 'CUDA': platform.setDefaultPropertyValue('CudaPrecision', precision) elif platform_name == 'OpenCL': platform.setDefaultPropertyValue('OpenCLPrecision', precision) potentials = list() states = list() for system in systems: integrator = openmm.VerletIntegrator(timestep) if platform: context = openmm.Context(system, integrator, platform) else: context = openmm.Context(system, integrator) context.setPositions(positions) state = context.getState(getEnergy=True, getPositions=True) potential = state.getPotentialEnergy() potentials.append(potential) states.append(state) del context, integrator logger.info("========") for i in range(len(systems)): logger.info( "%32s : %24.8f kcal/mol" % (descriptions[i], potentials[i] / units.kilocalories_per_mole)) integrator = openmm.VerletIntegrator(timestep) if platform: context = openmm.Context(systems[i], integrator, platform) else: context = openmm.Context(systems[i], integrator) context.setPositions(positions) state = context.getState(getEnergy=True, getPositions=True) potential = state.getPotentialEnergy() del context, integrator if (i > 0): delta = potentials[i] - potentials[0] logger.info("%32s : %24.8f kcal/mol" % ('ERROR', delta / units.kilocalories_per_mole)) if (abs(delta) > MAX_DELTA): raise Exception( "Maximum allowable deviation (%24.8f kcal/mol) exceeded; test failed." % (MAX_DELTA / units.kilocalories_per_mole)) return potentials
def _create_solvated_systems(self, database, initial_parameters): """ Create the solvated systems for the GB-HCT, OBC1, or OBC2 models Arguments --------- database : dict A dictionary of the FreeSolv database, prepared with vacuum openmm systems. initial_parameters : dict A dictionary of the initial parameters for the HCT force """ cid_list = database.keys() for (molecule_index, cid) in enumerate(cid_list): entry = database[cid] molecule = entry['molecule'] solvent_system = copy.deepcopy(entry['system']) forces = { solvent_system.getForce(index).__class__.__name__: solvent_system.getForce(index) for index in range(solvent_system.getNumForces()) } nonbonded_force = forces['NonbondedForce'] atoms = [atom for atom in molecule.GetAtoms()] gbsa_force = customgbforces.GBSAGBnForce(SA='ACE') for (atom_index, atom) in enumerate(atoms): [charge, sigma, epsilon] = nonbonded_force.getParticleParameters(atom_index) atomtype = atom.GetStringData("gbsa_type") # GBSA atomtype radius = initial_parameters['%s_%s' % (atomtype, 'radius')] * units.angstroms scalingFactor = initial_parameters['%s_%s' % (atomtype, 'scalingFactor')] gbsa_force.addParticle([charge, radius, scalingFactor]) solvent_system.addForce(gbsa_force) platform = openmm.Platform.getPlatformByName('CPU') timestep = 2.0 * units.femtosecond solvent_integrator = openmm.VerletIntegrator(timestep) solvent_context = openmm.Context(solvent_system, solvent_integrator, platform) entry['solvated_system'] = solvent_system entry['solvent_integrator'] = solvent_integrator entry['solvent_context'] = solvent_context vacuum_system = entry['system'] vacuum_integrator = openmm.VerletIntegrator(timestep) vacuum_context = openmm.Context(vacuum_system, vacuum_integrator, platform) entry['vacuum_integrator'] = vacuum_integrator entry['vacuum_context'] = vacuum_context database[cid] = entry return database
def compare_energy_components(rest_system, other_system, positions, platform=REFERENCE_PLATFORM): """ Get energy components of a given system """ platform = configure_platform(platform) # Create thermodynamic state and sampler state for non-rest system thermostate_other = ThermodynamicState(system=other_system, temperature=temperature) # Create context for non-rest system integrator_other = openmm.VerletIntegrator(1.0 * unit.femtosecond) context_other = thermostate_other.create_context(integrator_other) context_other.setPositions(positions) # Get energy components for non-rest system components_other = [ component[1] for component in compute_potential_components(context_other, beta=beta) ] # Create thermodynamic state for rest_system thermostate_rest = ThermodynamicState(system=rest_system, temperature=temperature) # Create context forrest system integrator_rest = openmm.VerletIntegrator(1.0 * unit.femtosecond) context_rest = thermostate_rest.create_context(integrator_rest) context_rest.setPositions(positions) # Get energy components for rest system components_rest = [ component[1] for component in compute_potential_components(context_rest, beta=beta) ] # Check that bond, angle, and torsion energies match for other, rest in zip(components_other[:3], components_rest[:3]): assert np.isclose( [other], [rest] ), f"The energies do not match for the {other[0]}: {other[1]} (other system) vs. {rest[1]} (REST system)" # Check that nonbonded energies match print(components_rest) nonbonded_other = np.array(components_other[3:]).sum() nonbonded_rest = np.array(components_rest[3:]).sum() assert np.isclose( [nonbonded_other], [nonbonded_rest] ), f"The energies do not match for the NonbondedForce: {nonbonded_other} (other system) vs. {nonbonded_rest} (REST system)"
def get_integrator(random_seed: int, args: ListOfArgs) -> mm.Integrator: """Helper function that returns requested integrator.""" print(" Integrator initialization...") integrator = mm.VerletIntegrator(10 * simtk.unit.femtosecond) # default integrator if args.SIM_RUN_SIMULATION: if args.SIM_INTEGRATOR_TYPE == "langevin": integrator = mm.LangevinIntegrator(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP) integrator.setRandomNumberSeed(random_seed) elif args.SIM_INTEGRATOR_TYPE == "brownian": print(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP) integrator = mm.BrownianIntegrator(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP) integrator.setRandomNumberSeed(random_seed) elif args.SIM_INTEGRATOR_TYPE == "verlet": integrator = mm.VerletIntegrator(args.SIM_TIME_STEP) return integrator
def test_tip3p_constraints(self): """Test that TIP3P distance costraints are correctly applied.""" # Specify TIP3P constraint distances tip3p_oh_distance = 0.9572 # angstrom tip3p_hoh_angle = 104.52 # angle tip3p_hh_distance = tip3p_oh_distance * np.sin(np.radians(tip3p_hoh_angle / 2)) * 2 expected_distances = [tip3p_oh_distance, tip3p_oh_distance, tip3p_hh_distance] # Load TIP3P molecule molecule = Molecule.from_file(tip3p_molecule_filename) # Extract topology and positions topology = Topology.from_molecules(molecule) positions = molecule.positions # Create OpenMM System ff = ForceField(tip3p_offxml_filename) system = ff.create_system(topology) # TODO: This is probably unnecessary and we can simply check that the System has all the Constraints in their position. # Run dynamics. integrator = openmm.VerletIntegrator(2.0 * unit.femtoseconds) context = openmm.Context(system, integrator) context.setPositions(positions) integrator.step(50) # Ensure constrained distances are correct state = context.getState(getPositions=True) new_positions = state.getPositions(asNumpy=True) / unit.angstroms distances = [] for atom_1, atom_2 in [(0, 1), (0, 2), (1, 2)]: # pair of atoms O-H1, O-H2, H1-H2 distances.append(np.linalg.norm(new_positions[atom_1] - new_positions[atom_2])) err_msg = 'expected distances [O-H1, O-H2, H1-H2]: {} A, new distances: {} A' assert np.allclose(expected_distances, distances), err_msg.format(expected_distances, distances)
def __init__(self, atoms): # Create a PDB file that can be read by OpenMM coords_to_pdb(atoms.get_positions(), int(atoms.get_number_of_atoms() / 3)) pdb = app.PDBFile("./tmp.pdb") os.remove('./tmp.pdb') cell = atoms.get_cell() # Make sure bond lengths are within MBPol range distances = atoms.get_all_distances() for i in range(0, len(distances), 3): for j in [1, 2]: if distances[i, i + j] > 2.5: print('WARNING: rOH > 2.5 A!!!!!! ({})'.format( distances[i, i + j])) if atoms.get_pbc()[0]: print('Try: reconnect_monomers()') self.atoms = atoms if np.count_nonzero(cell - np.diag(np.diag(cell))) != 0: raise Exception('Only orthorhombic unit cells supported') if np.alltrue(atoms.get_pbc()): self.nonbondedMethod = app.PME if np.allclose(np.diag(cell), np.array([0, 0, 0])): raise Exception('Specify unit cell for PBC') self.boxSize = tuple(np.diag(cell)) * unit.angstrom pdb.topology.setUnitCellDimensions(self.boxSize) self.nonbondedCutoff = cell[0, 0] / 2 * unit.angstrom elif np.alltrue([not a for a in atoms.get_pbc()]): self.nonbondedMethod = app.CutoffNonPeriodic self.nonbondedCutoff = 1e4 * unit.angstrom else: raise Exception( 'Only non-PBC or PBC in all euclidean directions supported') self.forcefield = app.ForceField( mbpol.__file__.replace("mbpol.py", "mbpol.xml")) self.system = self.forcefield.createSystem( pdb.topology, nonbondedMethod=self.nonbondedMethod, nonbondedCutoff=self.nonbondedCutoff) self.platform = mm.Platform.getPlatformByName('Reference') integrator = mm.VerletIntegrator( 0.5) # Never used but needed for context self.simulation = app.Simulation(pdb.topology, self.system, integrator, self.platform) self.set_positions(atoms) #ASE: Angstrom , OMM : nm self.state = self.simulation.context.getState(getForces=True, getEnergy=True) self.last_coordinates = np.array( pdb.positions.value_in_unit(unit.angstrom)) self.last_coordinates = np.delete(self.last_coordinates, np.arange(3, len(self.last_coordinates), 4), axis=0).reshape(-1, 3)
def _create_context(self, platform=None): """Create Integrator and Context objects if they do not already exist. """ # Check if we already have a Context defined. if self._context: #if platform and (platform != self._context.getPlatform()): # TODO: Figure out why requested and cached platforms differed in tests. if platform and ( platform.getName() != self._context.getPlatform().getName() ): # DEBUG: Only compare Platform names for now; change this later to incorporate GPU IDs. # Platform differs from the one requested; destroy it. logger.info((platform.getName(), self._context.getPlatform().getName())) logger.debug( "Platform differs from the one requested; destroying and recreating..." ) del self._context, self._integrator else: # Cached context is what we expect; do nothing. return # Create an integrator. timestep = 1.0 * units.femtosecond self._integrator = mm.VerletIntegrator(timestep) # Create a new OpenMM context. if platform: self._context = mm.Context(self.system, self._integrator, platform) else: self._context = mm.Context(self.system, self._integrator) logger.debug("_create_context created a new integrator and context")
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 __init__(self, molecule, pdb, xml, combination='amber'): try: import simtk.openmm.app as app import simtk.openmm as mm import simtk.unit as u except ImportError: raise ImportError("OpenMM computation object requires the 'simtk' package. Please pip or conda install 'openmm' from omnia channel.") pdb = app.PDBFile(pdb) xmlSystem = False if os.path.exists(xml): xmlStr = open(xml).read() try: # If the user has provided an OpenMM system, we can use it directly system = mm.XmlSerializer.deserialize(xmlStr) xmlSystem = True logger.info("Treating the provided xml as a system XML file") except ValueError: logger.info("Treating the provided xml as a force field XML file") else: logger.info("xml file not in the current folder, treating as a force field XML file and setting up in gas phase.") if not xmlSystem: forcefield = app.ForceField(xml) system = forcefield.createSystem(pdb.topology, nonbondedMethod=app.NoCutoff, constraints=None, rigidWater=False) # apply opls combination rule if we are using it if combination == 'opls': system = self.opls(system) integrator = mm.VerletIntegrator(1.0*u.femtoseconds) platform = mm.Platform.getPlatformByName('Reference') self.simulation = app.Simulation(pdb.topology, system, integrator, platform) super(OpenMM, self).__init__(molecule)
def mm_potential(self, forcefield, top, xyz, charge=False): if isinstance(charge, bool): if (charge): system = forcefield.create_openmm_system(top) else: mols = [ Molecule(mol.reference_molecule) for mol in top.topology_molecules ] for i, _ in enumerate(mols): mols[i].partial_charges = simtk.unit.Quantity( np.zeros(mols[i].n_atoms), simtk.unit.elementary_charge) system = forcefield.create_openmm_system( top, charge_from_molecules=mols) else: mols = [ Molecule(mol.reference_molecule) for mol in top.topology_molecules ] for i, _ in enumerate(mols): mols[i].partial_charges = charge[i] system = forcefield.create_openmm_system( top, charge_from_molecules=mols) integrator = openmm.VerletIntegrator(1.0 * simtk.unit.femtoseconds) context = openmm.Context(system, integrator) context.setPositions(xyz * const.angstrom2nm) state = context.getState(getEnergy=True) energy = state.getPotentialEnergy().in_units_of( simtk.unit.kilocalories_per_mole) return energy
def g_k(self, molecule_smiles): """ Retrieve or compute the g_k for the given molecule Parameters ---------- molecule_smiles : string SMILES representation of the molecule Returns ------- g_k : float Bias weight """ if molecule_smiles in self._gk.keys(): return self._gk[molecule_smiles] else: system, positions = self._create_implicit_solvent_openmm( self._mol_dict[molecule_smiles]) timestep = 2 * units.femtoseconds integrator = openmm.VerletIntegrator(timestep) platform = openmm.Platform.getPlatformByName("CPU") context = openmm.Context(system, integrator, platform) context.setPositions(positions) openmm.LocalEnergyMinimizer.minimize(context) state = context.getState(getEnergy=True) g_k = state.getPotentialEnergy() self._gk[molecule_smiles] = g_k return g_k
def compute_reduced_potential(thermodynamic_state: states.ThermodynamicState, sampler_state: states.SamplerState) -> float: """ Compute the reduced potential of the given SamplerState under the given ThermodynamicState. Arguments ---------- thermodynamic_state : openmmtools.states.ThermodynamicState The thermodynamic state under which to compute the reduced potential sampler_state : openmmtools.states.SamplerState The sampler state for which to compute the reduced potential Returns ------- reduced_potential : float unitless reduced potential (kT) """ if type(cache.global_context_cache) == cache.DummyContextCache: integrator = openmm.VerletIntegrator( 1.0) #we won't take any steps, so use a simple integrator context, integrator = cache.global_context_cache.get_context( thermodynamic_state, integrator) else: context, integrator = cache.global_context_cache.get_context( thermodynamic_state) sampler_state.apply_to_context(context, ignore_velocities=True) return thermodynamic_state.reduced_potential(context)
def testForce(self): # Create a random cloud of particles. numParticles = 10 system = mm.System() positions = np.random.rand(numParticles, 3) for i in range(numParticles): system.addParticle(1.0) force = ot.TorchForce("../../tests/central.pt") system.addForce(force) # Compute the forces and energy. integ = mm.VerletIntegrator(1.0) context = mm.Context(system, integ, mm.Platform.getPlatformByName('Reference')) context.setPositions(positions) state = context.getState(getEnergy=True, getForces=True) # See if the energy and forces are correct. The network defines a potential of the form E(r) = |r|^2 expectedEnergy = np.sum(positions * positions) assert np.allclose( expectedEnergy, state.getPotentialEnergy().value_in_unit(unit.kilojoules_per_mole)) assert np.allclose(-2 * positions, state.getForces(asNumpy=True))
def test_try_random_itoc(): """ test whether a perturbed four-atom system gives the same internal and cartesian coords when recomputed with `_internal_to_cartesian` and `_cartesian_to_internal` as compared to the values output by `_get_internal_from_omm` """ import perses.rjmc.geometry as geometry geometry_engine = geometry.FFAllAngleGeometryEngine({'test': 'true'}) import simtk.openmm as openmm integrator = openmm.VerletIntegrator(1.0*unit.femtoseconds) sys = openmm.System() force = openmm.CustomTorsionForce("theta") for i in range(4): sys.addParticle(1.0*unit.amu) force.addTorsion(0,1,2,3,[]) sys.addForce(force) atom_position = unit.Quantity(np.array([ 0.10557722 ,-1.10424644 ,-1.08578826]), unit=unit.nanometers) bond_position = unit.Quantity(np.array([ 0.0765, 0.1 , -0.4005]), unit=unit.nanometers) angle_position = unit.Quantity(np.array([ 0.0829 , 0.0952 ,-0.2479]) ,unit=unit.nanometers) torsion_position = unit.Quantity(np.array([-0.057 , 0.0951 ,-0.1863] ) ,unit=unit.nanometers) for i in range(1000): atom_position += unit.Quantity(np.random.normal(size=3), unit=unit.nanometers) r, theta, phi = _get_internal_from_omm(atom_position, bond_position, angle_position, torsion_position) recomputed_xyz, _ = geometry_engine._internal_to_cartesian(bond_position, angle_position, torsion_position, r, theta, phi) new_r, new_theta, new_phi = _get_internal_from_omm(recomputed_xyz,bond_position, angle_position, torsion_position) TOLERANCE = 1e-10 difference = np.linalg.norm(np.array(atom_position/unit.nanometers) - np.array(recomputed_xyz/unit.nanometers)) assert difference < TOLERANCE, f"the norm of the difference in positions recomputed with original cartesians ({difference}) is greater than tolerance of {TOLERANCE}" difference = np.linalg.norm(np.array([r, theta, phi]) - np.array([new_r, new_theta, new_phi])) assert difference < TOLERANCE, f"the norm of the difference in internals recomputed with original sphericals ({difference}) is greater than tolerance of {TOLERANCE}"
def check_potential_energy(system, positions): """ Compute potential energy for system and positions and ensure that it is finite. Parameters ---------- system : simtk.openmm.System The system positions : simtk.unit.Quantity The positions """ # Create a Context. timestep = 1.0 * unit.femtoseconds integrator = openmm.VerletIntegrator(timestep) context = openmm.Context(system, integrator) context.setPositions(positions) # Compute potential energy to make sure it is finite. openmm_state = context.getState(getEnergy=True) potential_energy = openmm_state.getPotentialEnergy() # Check if finite. if np.isnan(potential_energy / unit.kilocalories_per_mole): raise Exception("Energy is NaN.") # Clean up del context, integrator
def create_sim(self): self.system = self.top.createSystem(nonbondedMethod=app.NoCutoff, constraints=None) self.integrator = openmm.VerletIntegrator(0.001 * unit.picoseconds) self.simulation = app.Simulation(self.top.topology, self.system, self.integrator) self.simulation.context.setPositions(self.trj.openmm_positions(0))
def _create_torsion_sim(periodicity: int = 2, phase=0 * omm_angle_unit, k=10.0 * omm_energy_unit) -> app.Simulation: """Create a 4-particle OpenMM Simulation containing only a PeriodicTorsionForce""" system = mm.System() # add 4 particles of unit mass for _ in range(4): system.addParticle(1) # add torsion force to system force = mm.PeriodicTorsionForce() force.addTorsion(0, 1, 2, 3, periodicity, phase, k) system.addForce(force) # create openmm Simulation, which requires a Topology and Integrator topology = app.Topology() chain = topology.addChain() residue = topology.addResidue("torsion", chain) for name in ["a", "b", "c", "d"]: topology.addAtom(name, "C", residue) integrator = mm.VerletIntegrator(1.0) sim = app.Simulation(topology, system, integrator) return sim
def compute_potential_components(context): """ Compute potential energy, raising an exception if it is not finite. Parameters ---------- context : simtk.openmm.Context The context from which to extract, System, parameters, and positions. """ import copy system = context.getSystem() system = copy.deepcopy(system) positions = context.getState(getPositions=True).getPositions(asNumpy=True) parameters = context.getParameters() for index in range(system.getNumForces()): force = system.getForce(index) force.setForceGroup(index) integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds) platform = openmm.Platform.getPlatformByName('Reference') context = openmm.Context(system, integrator, platform) context.setPositions(positions) for (parameter, value) in parameters.items(): context.setParameter(parameter, value) energy_components = list() for index in range(system.getNumForces()): force = system.getForce(index) forcename = force.__class__.__name__ groups = 1<<index potential = context.getState(getEnergy=True, groups=groups).getPotentialEnergy() energy_components.append((forcename, potential)) del context, integrator return energy_components
def compute_potential(system, positions, platform=None): """ Compute potential energy, raising an exception if it is not finite. Parameters ---------- system : simtk.openmm.System The system object to check. positions : simtk.unit.Quantity of size (natoms,3) with units compatible with nanometers The positions to check. platform : simtk.openmm.Platform, optional, default=none If specified, this platform will be used. """ integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds) if platform is not None: context = openmm.Context(system, integrator, platform) else: context = openmm.Context(system, integrator) context.setPositions(positions) context.applyConstraints(integrator.getConstraintTolerance()) potential = context.getState(getEnergy=True).getPotentialEnergy() del context, integrator if np.isnan(potential / unit.kilocalories_per_mole): raise NaNException("Potential energy is NaN") return potential
def minimize(thermodynamic_state, sampler_state, max_iterations=100): """ Minimize the given system and state, up to a maximum number of steps. This does not return a copy of the samplerstate; it is simply an update-in-place. Arguments ---------- thermodynamic_state : openmmtools.states.ThermodynamicState The state at which the system could be minimized sampler_state : openmmtools.states.SamplerState The starting state at which to minimize the system. max_iterations : int, optional, default 20 The maximum number of minimization steps. Default is 100. Returns ------- sampler_state : openmmtools.states.SamplerState The posititions and accompanying state following minimization """ if type(cache.global_context_cache) == cache.DummyContextCache: integrator = openmm.VerletIntegrator( 1.0) #we won't take any steps, so use a simple integrator context, integrator = cache.global_context_cache.get_context( thermodynamic_state, integrator) _logger.debug(f"using dummy context cache") else: _logger.debug(f"using global context cache") context, integrator = cache.global_context_cache.get_context( thermodynamic_state) sampler_state.apply_to_context(context, ignore_velocities=True) openmm.LocalEnergyMinimizer.minimize(context, maxIterations=max_iterations) sampler_state.update_from_context(context)
def check_potential_is_finite(system, positions): """ Check that the potential energy is finite. Parameters ---------- system : simtk.openmm.Syste System object positions : simtk.unit.Quantity of (natoms,3) with units compatible with angstroms positions Returns ------- potential : simtk.unit.Quantity The potential energy. Raises an Exception if the potential energy is not finite. """ integrator = openmm.VerletIntegrator(1 * unit.femtoseconds) context = openmm.Context(system, integrator) context.setPositions(positions) potential = context.getState(getEnergy=True).getPotentialEnergy() del context, integrator if np.isnan(potential / unit.kilojoules_per_mole): raise Exception("Potential energy is infinite.") return potential
def create_system(self): # set up the system using opls combo rules # Load the initial coords into the system and initialise forcefield = app.ForceField(self.xml_file) top = self.molecule.to_openmm_topology() positions = self.molecule.openmm_coordinates() # set the initial positions from the pdb modeller = app.Modeller(topology=top, positions=positions) # if there are virtual sites we need to add them here try: self.system = forcefield.createSystem(modeller.topology, nonbondedMethod=app.NoCutoff, constraints=None) except ValueError: print("Virtual sites were found in the xml file") modeller.addExtraParticles(forcefield) self.system = forcefield.createSystem(modeller.topology, nonbondedMethod=app.NoCutoff, constraints=None) # Use the opls combination rules. if self.molecule.combination == "opls": print("OPLS combination rules found in XML file") self.opls_lj() integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds) platform = openmm.Platform.getPlatformByName("Reference") self.simulation = app.Simulation(modeller.topology, self.system, integrator, platform) self.simulation.context.setPositions(modeller.positions)
def test_amber_implicit(prmtop_filename, inpcrd_filename): logger.info("====================================================================") logger.info("Creating system...") from simtk.openmm import app prmtop = app.AmberPrmtopFile(prmtop_filename) reference_system = prmtop.createSystem(constraints=app.HBonds, nonbondedMethod=app.NoCutoff, implicitSolvent=app.OBC1) # Read positions. inpcrd = app.AmberInpcrdFile(inpcrd_filename, loadBoxVectors=False) positions = inpcrd.getPositions(asNumpy=True) # Set box vectors. #box_vectors = inpcrd.getBoxVectors(asNumpy=True) #system.setDefaultPeriodicBoxVectors(box_vectors[0], box_vectors[1], box_vectors[2]) receptor_atoms = range(0,1326) ligand_atoms = range(1326, 1356) # Minimize. logger.info("Minimizing...") timestep = 1.0 * units.femtoseconds integrator = openmm.VerletIntegrator(timestep) context = openmm.Context(reference_system, integrator) context.setPositions(positions) openmm.LocalEnergyMinimizer.minimize(context, 1.0, 100) state = context.getState(getEnergy=True, getPositions=True) positions = state.getPositions(asNumpy=True) del context, integrator logger.info("Done.") alchemical_factory_check(reference_system, positions, receptor_atoms, ligand_atoms) #benchmark(reference_system, positions, receptor_atoms, ligand_atoms) logger.info("====================================================================") logger.info("")