def benchmark(reference_system, positions, receptor_atoms, ligand_atoms, platform_name=None, annihilateElectrostatics=True, annihilateSterics=False, nsteps=500): """ Benchmark performance relative to unmodified system. ARGUMENTS reference_system (simtk.openmm.System) - the reference System object to compare with positions - 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 """ # Create a factory to produce alchemical intermediates. logger.info("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 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(0.00, lambda_value, lambda_value, lambda_value) alchemical_state.annihilateElectrostatics = annihilateElectrostatics alchemical_state.annihilateSterics = annihilateSterics 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. timestep = 1.0 * units.femtosecond 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
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 * units.kelvin collision_rate = 5.0 / units.picoseconds timestep = 2.0 * units.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 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(0.00, 1.00, 1.00, 1.0) alchemical_system = factory.createPerturbedSystem(alchemical_state) temperature = 300.0 * units.kelvin collision_rate = 5.0 / units.picoseconds timestep = 2.0 * units.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*units.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
def benchmark(reference_system, positions, receptor_atoms, ligand_atoms, platform_name=None, annihilate_electrostatics=True, annihilate_sterics=False, nsteps=500, timestep=1.0 * units.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(0.00, lambda_value, lambda_value, 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