def benchmark(reference_system, positions, platform_name=None, nsteps=500, timestep=1.0*unit.femtoseconds, factory_args=None): """ Benchmark performance of alchemically modified system relative to original system. Parameters ---------- reference_system : simtk.openmm.System The reference System object to compare with positions : simtk.unit.Quantity with units compatible with nanometers The positions to assess energetics for. platform_name : str, optional, default=None The name of the platform to use for benchmarking. nsteps : int, optional, default=500 Number of molecular dynamics steps to use for benchmarking. timestep : simtk.unit.Quantity with units compatible with femtoseconds, optional, default=1*femtoseconds Timestep to use for benchmarking. factory_args : dict(), optional, default=None Arguments passed to AbsoluteAlchemicalFactory. """ from alchemy import AbsoluteAlchemicalFactory, AlchemicalState # Create a factory to produce alchemical intermediates. print("Creating alchemical factory...") initial_time = time.time() factory = AbsoluteAlchemicalFactory(reference_system, **factory_args) 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(lambda_electrostatics=lambda_value, lambda_sterics=lambda_value, lambda_torsions=lambda_value) platform = None if platform_name: platform = openmm.Platform.getPlatformByName(platform_name) temperature = 300.*unit.kelvin collision_rate = 90./unit.picoseconds # 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. print("Computing reference energies...") reference_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) if platform: reference_context = openmm.Context(reference_system, reference_integrator, platform) else: reference_context = openmm.Context(reference_system, reference_integrator) reference_context.setPositions(positions) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() print(reference_potential) print("Computing alchemical energies...") alchemical_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) if platform: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) else: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator) alchemical_context.setPositions(positions) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() print(reference_potential) # Make sure all kernels are compiled. reference_integrator.step(2) alchemical_integrator.step(2) # Time simulations. print("Simulating reference system...") initial_time = time.time() reference_integrator.step(nsteps) reference_state = reference_context.getState() #reference_state = reference_context.getState(getEnergy=True) #reference_potential = reference_state.getPotentialEnergy() final_time = time.time() reference_time = final_time - initial_time print("Simulating alchemical system...") initial_time = time.time() alchemical_integrator.step(nsteps) reference_state = alchemical_context.getState() #alchemical_state = alchemical_context.getState(getEnergy=True) #alchemical_potential = alchemical_state.getPotentialEnergy() final_time = time.time() alchemical_time = final_time - initial_time seconds_per_day = (1.*unit.day)/(1.*unit.seconds) print("TIMINGS") print("reference system : %12.3f s for %8d steps (%12.3f ms/step; %12.3f ns/day)" % (reference_time, nsteps, reference_time/nsteps*1000, nsteps*timestep*(seconds_per_day/reference_time)/unit.nanoseconds)) print("alchemical system : %12.3f s for %8d steps (%12.3f ms/step; %12.3f ns/day)" % (alchemical_time, nsteps, alchemical_time/nsteps*1000, nsteps*timestep*(seconds_per_day/alchemical_time)/unit.nanoseconds)) print("alchemical simulation is %12.3f x slower than unperturbed system" % (alchemical_time / reference_time))
def benchmark(reference_system, positions, platform_name=None, nsteps=500, timestep=1.0 * unit.femtoseconds, factory_args=None): """ Benchmark performance of alchemically modified system relative to original system. Parameters ---------- reference_system : simtk.openmm.System The reference System object to compare with positions : simtk.unit.Quantity with units compatible with nanometers The positions to assess energetics for. platform_name : str, optional, default=None The name of the platform to use for benchmarking. nsteps : int, optional, default=500 Number of molecular dynamics steps to use for benchmarking. timestep : simtk.unit.Quantity with units compatible with femtoseconds, optional, default=1*femtoseconds Timestep to use for benchmarking. factory_args : dict(), optional, default=None Arguments passed to AbsoluteAlchemicalFactory. """ from alchemy import AbsoluteAlchemicalFactory, AlchemicalState # Create a factory to produce alchemical intermediates. print("Creating alchemical factory...") initial_time = time.time() factory = AbsoluteAlchemicalFactory(reference_system, **factory_args) 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(lambda_electrostatics=lambda_value, lambda_sterics=lambda_value, lambda_torsions=lambda_value) platform = None if platform_name: platform = openmm.Platform.getPlatformByName(platform_name) temperature = 300. * unit.kelvin collision_rate = 90. / unit.picoseconds # 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. print("Computing reference energies...") reference_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) if platform: reference_context = openmm.Context(reference_system, reference_integrator, platform) else: reference_context = openmm.Context(reference_system, reference_integrator) reference_context.setPositions(positions) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() print(reference_potential) print("Computing alchemical energies...") alchemical_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) if platform: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) else: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator) alchemical_context.setPositions(positions) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() print(reference_potential) # Make sure all kernels are compiled. reference_integrator.step(2) alchemical_integrator.step(2) # Time simulations. print("Simulating reference system...") initial_time = time.time() reference_integrator.step(nsteps) reference_state = reference_context.getState() #reference_state = reference_context.getState(getEnergy=True) #reference_potential = reference_state.getPotentialEnergy() final_time = time.time() reference_time = final_time - initial_time print("Simulating alchemical system...") initial_time = time.time() alchemical_integrator.step(nsteps) reference_state = alchemical_context.getState() #alchemical_state = alchemical_context.getState(getEnergy=True) #alchemical_potential = alchemical_state.getPotentialEnergy() final_time = time.time() alchemical_time = final_time - initial_time seconds_per_day = (1. * unit.day) / (1. * unit.seconds) print("TIMINGS") print( "reference system : %12.3f s for %8d steps (%12.3f ms/step; %12.3f ns/day)" % (reference_time, nsteps, reference_time / nsteps * 1000, nsteps * timestep * (seconds_per_day / reference_time) / unit.nanoseconds)) print( "alchemical system : %12.3f s for %8d steps (%12.3f ms/step; %12.3f ns/day)" % (alchemical_time, nsteps, alchemical_time / nsteps * 1000, nsteps * timestep * (seconds_per_day / alchemical_time) / unit.nanoseconds)) print("alchemical simulation is %12.3f x slower than unperturbed system" % (alchemical_time / reference_time))
def testAlchemicalFactory(reference_system, coordinates, receptor_atoms, ligand_atoms, platform_name='Reference', annihilateElectrostatics=True, annihilateLennardJones=False): """ 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 receptor_atoms (list of int) - the list of receptor atoms ligand_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, ligand_atoms=ligand_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) alchemical_state.annihilateElectrostatics = annihilateElectrostatics alchemical_state.annihilateLennardJones = annihilateLennardJones #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 benchmark( reference_system, coordinates, receptor_atoms, ligand_atoms, platform_name="CUDA", annihilateElectrostatics=True, annihilateLennardJones=False, nsteps=500, ): """ Benchmark performance relative to unmodified system. ARGUMENTS reference_system (simtk.openmm.System) - the reference System object to compare with coordinates - the coordinates to assess energetics for receptor_atoms (list of int) - the list of receptor atoms ligand_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, ligand_atoms=ligand_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) alchemical_state.annihilateElectrostatics = annihilateElectrostatics alchemical_state.annihilateLennardJones = annihilateLennardJones 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 # Make sure all kernels are compiled. reference_integrator.step(1) alchemical_integrator.step(1) # Time simulations. import time print "Simulating reference system..." initial_time = time.time() reference_integrator.step(nsteps) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() final_time = time.time() reference_time = final_time - initial_time print "Simulating alchemical system..." initial_time = time.time() alchemical_integrator.step(nsteps) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() final_time = time.time() alchemical_time = final_time - initial_time print "TIMINGS" print "reference system : %12.3f s for %8d steps (%12.3f ms/step)" % ( reference_time, nsteps, reference_time / nsteps * 1000, ) print "alchemical system : %12.3f s for %8d steps (%12.3f ms/step)" % ( alchemical_time, nsteps, alchemical_time / nsteps * 1000, ) print "alchemical simulation is %12.3f x slower than unperturbed system" % (alchemical_time / reference_time) return delta
def overlap_check(reference_system, positions, platform_name=None, precision=None, nsteps=50, nsamples=200, factory_args=None, cached_trajectory_filename=None): """ Test overlap between reference system and alchemical system by running a short simulation. Parameters ---------- reference_system : simtk.openmm.System The reference System object to compare with positions : simtk.unit.Quantity with units compatible with nanometers The positions to assess energetics for. platform_name : str, optional, default=None The name of the platform to use for benchmarking. nsteps : int, optional, default=50 Number of molecular dynamics steps between samples. nsamples : int, optional, default=100 Number of samples to collect. factory_args : dict(), optional, default=None Arguments passed to AbsoluteAlchemicalFactory. cached_trajectory_filename : str, optional, default=None If specified, attempt to cache (or reuse) trajectory. """ # Create a fully-interacting alchemical state. factory = AbsoluteAlchemicalFactory(reference_system, **factory_args) alchemical_state = AlchemicalState() alchemical_system = factory.createPerturbedSystem(alchemical_state) temperature = 300.0 * unit.kelvin collision_rate = 5.0 / unit.picoseconds timestep = 2.0 * unit.femtoseconds kT = (kB * temperature) # Select platform. platform = None if platform_name: platform = openmm.Platform.getPlatformByName(platform_name) # Create integrators. reference_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) alchemical_integrator = openmm.VerletIntegrator(timestep) # Create contexts. if platform: reference_context = openmm.Context(reference_system, reference_integrator, platform) alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) else: reference_context = openmm.Context(reference_system, reference_integrator) alchemical_context = openmm.Context(alchemical_system, alchemical_integrator) ncfile = None if cached_trajectory_filename: cache_mode = 'write' # Try reading from cache from netCDF4 import Dataset if os.path.exists(cached_trajectory_filename): try: ncfile = Dataset(cached_trajectory_filename, 'r') if (ncfile.variables['positions'].shape == (nsamples, reference_system.getNumParticles(), 3)): # Read the cache if everything matches cache_mode = 'read' except: pass if cache_mode == 'write': # If anything went wrong, create a new cache. try: (pathname, filename) = os.path.split(cached_trajectory_filename) if not os.path.exists(pathname): os.makedirs(pathname) ncfile = Dataset(cached_trajectory_filename, 'w', format='NETCDF4') ncfile.createDimension('samples', 0) ncfile.createDimension('atoms', reference_system.getNumParticles()) ncfile.createDimension('spatial', 3) ncfile.createVariable('positions', 'f4', ('samples', 'atoms', 'spatial')) except Exception as e: logger.info(str(e)) logger.info('Could not create a trajectory cache (%s).' % cached_trajectory_filename) ncfile = None # Collect simulation data. reference_context.setPositions(positions) du_n = np.zeros([nsamples], np.float64) # du_n[n] is the print() import click with click.progressbar(range(nsamples)) as bar: for sample in bar: if cached_trajectory_filename and (cache_mode == 'read'): # Load cached frames. positions = unit.Quantity(ncfile.variables['positions'][sample,:,:], unit.nanometers) reference_context.setPositions(positions) else: # Run dynamics. reference_integrator.step(nsteps) # Get reference energies. reference_state = reference_context.getState(getEnergy=True, getPositions=True) reference_potential = reference_state.getPotentialEnergy() if np.isnan(reference_potential/kT): raise Exception("Reference potential is NaN") # Get alchemical energies. alchemical_context.setPositions(reference_state.getPositions(asNumpy=True)) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() if np.isnan(alchemical_potential/kT): raise Exception("Alchemical potential is NaN") du_n[sample] = (alchemical_potential - reference_potential) / kT if cached_trajectory_filename and (cache_mode == 'write') and (ncfile is not None): ncfile.variables['positions'][sample,:,:] = reference_state.getPositions(asNumpy=True) / unit.nanometers # Clean up. del reference_context, alchemical_context if cached_trajectory_filename and (ncfile is not None): ncfile.close() # Discard data to equilibration and subsample. from pymbar import timeseries [t0, g, Neff] = timeseries.detectEquilibration(du_n) indices = timeseries.subsampleCorrelatedData(du_n, g=g) du_n = du_n[indices] # Compute statistics. from pymbar import EXP [DeltaF, dDeltaF] = EXP(du_n) # Raise an exception if the error is larger than 3kT. MAX_DEVIATION = 3.0 # kT if (dDeltaF > MAX_DEVIATION): report = "DeltaF = %12.3f +- %12.3f kT (%5d samples, g = %6.1f)" % (DeltaF, dDeltaF, Neff, g) raise Exception(report) return
def overlap_check( reference_system, positions, receptor_atoms, ligand_atoms, platform_name=None, annihilate_electrostatics=True, annihilate_sterics=False, precision=None, nsteps=50, nsamples=200, ): """ Test overlap between reference system and alchemical system by running a short simulation. Parameters ---------- reference_system : simtk.openmm.System The reference System object to compare with positions : simtk.unit.Quantity with units compatible with nanometers The positions to assess energetics for. receptor_atoms : list of int The list of receptor atoms. ligand_atoms : list of int The list of ligand atoms to alchemically modify. platform_name : str, optional, default=None The name of the platform to use for benchmarking. annihilate_electrostatics : bool, optional, default=True If True, electrostatics will be annihilated; if False, decoupled. annihilate_sterics : bool, optional, default=False If True, sterics will be annihilated; if False, decoupled. nsteps : int, optional, default=50 Number of molecular dynamics steps between samples. nsamples : int, optional, default=100 Number of samples to collect. """ # Create a fully-interacting alchemical state. factory = AbsoluteAlchemicalFactory(reference_system, ligand_atoms=ligand_atoms) alchemical_state = AlchemicalState() alchemical_system = factory.createPerturbedSystem(alchemical_state) temperature = 300.0 * unit.kelvin collision_rate = 5.0 / unit.picoseconds timestep = 2.0 * unit.femtoseconds kT = kB * temperature # Select platform. platform = None if platform_name: platform = openmm.Platform.getPlatformByName(platform_name) # Create integrators. reference_integrator = openmm.LangevinIntegrator(temperature, collision_rate, timestep) alchemical_integrator = openmm.VerletIntegrator(timestep) # Create contexts. if platform: reference_context = openmm.Context(reference_system, reference_integrator, platform) alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) else: reference_context = openmm.Context(reference_system, reference_integrator) alchemical_context = openmm.Context(alchemical_system, alchemical_integrator) # Collect simulation data. reference_context.setPositions(positions) du_n = np.zeros([nsamples], np.float64) # du_n[n] is the for sample in range(nsamples): # Run dynamics. reference_integrator.step(nsteps) # Get reference energies. reference_state = reference_context.getState(getEnergy=True, getPositions=True) reference_potential = reference_state.getPotentialEnergy() # Get alchemical energies. alchemical_context.setPositions(reference_state.getPositions()) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() du_n[sample] = (alchemical_potential - reference_potential) / kT # Clean up. del reference_context, alchemical_context # Discard data to equilibration and subsample. from pymbar import timeseries [t0, g, Neff] = timeseries.detectEquilibration(du_n) indices = timeseries.subsampleCorrelatedData(du_n, g=g) du_n = du_n[indices] # Compute statistics. from pymbar import EXP [DeltaF, dDeltaF] = EXP(du_n) # Raise an exception if the error is larger than 3kT. MAX_DEVIATION = 3.0 # kT if dDeltaF > MAX_DEVIATION: report = "DeltaF = %12.3f +- %12.3f kT (%5d samples, g = %6.1f)" % (DeltaF, dDeltaF, Neff, g) raise Exception(report) return
def benchmark( reference_system, positions, receptor_atoms, ligand_atoms, platform_name=None, annihilate_electrostatics=True, annihilate_sterics=False, nsteps=500, timestep=1.0 * unit.femtoseconds, ): """ Benchmark performance of alchemically modified system relative to original system. Parameters ---------- reference_system : simtk.openmm.System The reference System object to compare with positions : simtk.unit.Quantity with units compatible with nanometers The positions to assess energetics for. receptor_atoms : list of int The list of receptor atoms. ligand_atoms : list of int The list of ligand atoms to alchemically modify. platform_name : str, optional, default=None The name of the platform to use for benchmarking. annihilate_electrostatics : bool, optional, default=True If True, electrostatics will be annihilated; if False, decoupled. annihilate_sterics : bool, optional, default=False If True, sterics will be annihilated; if False, decoupled. nsteps : int, optional, default=500 Number of molecular dynamics steps to use for benchmarking. timestep : simtk.unit.Quantity with units compatible with femtoseconds, optional, default=1*femtoseconds Timestep to use for benchmarking. """ # Create a factory to produce alchemical intermediates. logger.info("Creating alchemical factory...") initial_time = time.time() factory = AbsoluteAlchemicalFactory( reference_system, ligand_atoms=ligand_atoms, annihilate_electrostatics=annihilate_electrostatics, annihilate_sterics=annihilate_sterics, ) final_time = time.time() elapsed_time = final_time - initial_time logger.info("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( lambda_coulomb=lambda_value, lambda_sterics=lambda_value, lambda_torsions=lambda_value ) platform = None if platform_name: platform = openmm.Platform.getPlatformByName(platform_name) # Create the perturbed system. logger.info("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. logger.info("Computing reference energies...") reference_integrator = openmm.VerletIntegrator(timestep) if platform: reference_context = openmm.Context(reference_system, reference_integrator, platform) else: reference_context = openmm.Context(reference_system, reference_integrator) reference_context.setPositions(positions) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() logger.info("Computing alchemical energies...") alchemical_integrator = openmm.VerletIntegrator(timestep) if platform: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator, platform) else: alchemical_context = openmm.Context(alchemical_system, alchemical_integrator) alchemical_context.setPositions(positions) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() delta = alchemical_potential - reference_potential # Make sure all kernels are compiled. reference_integrator.step(1) alchemical_integrator.step(1) # Time simulations. logger.info("Simulating reference system...") initial_time = time.time() reference_integrator.step(nsteps) reference_state = reference_context.getState(getEnergy=True) reference_potential = reference_state.getPotentialEnergy() final_time = time.time() reference_time = final_time - initial_time logger.info("Simulating alchemical system...") initial_time = time.time() alchemical_integrator.step(nsteps) alchemical_state = alchemical_context.getState(getEnergy=True) alchemical_potential = alchemical_state.getPotentialEnergy() final_time = time.time() alchemical_time = final_time - initial_time logger.info("TIMINGS") logger.info( "reference system : %12.3f s for %8d steps (%12.3f ms/step)" % (reference_time, nsteps, reference_time / nsteps * 1000) ) logger.info( "alchemical system : %12.3f s for %8d steps (%12.3f ms/step)" % (alchemical_time, nsteps, alchemical_time / nsteps * 1000) ) logger.info("alchemical simulation is %12.3f x slower than unperturbed system" % (alchemical_time / reference_time)) return delta