def test_external_protocol_work_accumulation(): """When `measure_protocol_work==True`, assert that global `protocol_work` is initialized to zero and reaches a zero value after integrating a few dozen steps without perturbation. By default (`measure_protocol_work=False`), assert that there is no global name for `protocol_work`.""" testsystem = testsystems.HarmonicOscillator() system, topology = testsystem.system, testsystem.topology temperature = 298.0 * unit.kelvin integrator = integrators.ExternalPerturbationLangevinIntegrator(splitting="O V R V O", temperature=temperature) context = openmm.Context(system, integrator) context.setPositions(testsystem.positions) context.setVelocitiesToTemperature(temperature) # Check that initial step accumulates no protocol work assert(integrator.get_protocol_work(dimensionless=True) == 0), "Protocol work should be 0 initially" assert(integrator.get_protocol_work() / unit.kilojoules_per_mole == 0), "Protocol work should have units of energy" integrator.step(1) assert(integrator.get_protocol_work(dimensionless=True) == 0), "There should be no protocol work." # Check that a single step accumulates protocol work pe_1 = context.getState(getEnergy=True).getPotentialEnergy() perturbed_K=99.0 * unit.kilocalories_per_mole / unit.angstroms**2 context.setParameter('testsystems_HarmonicOscillator_K', perturbed_K) pe_2 = context.getState(getEnergy=True).getPotentialEnergy() integrator.step(1) assert (integrator.get_protocol_work(dimensionless=True) != 0), "There should be protocol work after perturbing." assert (integrator.protocol_work == (pe_2 - pe_1)), "The potential energy difference should be equal to protocol work." del context, integrator integrator = integrators.VVVRIntegrator(temperature) context = openmm.Context(system, integrator) context.setPositions(testsystem.positions) context.setVelocitiesToTemperature(temperature) integrator.step(25) del context, integrator
def create_system(self, testsystem, parameter_name, parameter_initial, temperature=298.0 * unit.kelvin, platform_name='Reference'): """ Create an example system to be used by other tests """ system, topology = testsystem.system, testsystem.topology integrator = integrators.ExternalPerturbationLangevinIntegrator( splitting="O V R V O", temperature=temperature) # Create the context platform = openmm.Platform.getPlatformByName(platform_name) if platform_name in ['CPU', 'CUDA']: try: platform.setPropertyDefaultValue('DeterministicForces', 'true') except Exception as e: mm_min_version = '7.2.0' if platform_name == 'CPU' and openmm.version.short_version < mm_min_version: print( "Deterministic CPU forces not present in versions of OpenMM prior to {}" .format(mm_min_version)) else: raise e context = openmm.Context(system, integrator, platform) context.setParameter(parameter_name, parameter_initial) context.setPositions(testsystem.positions) context.setVelocitiesToTemperature(temperature) return context, integrator
def create_system(self, testsystem, parameter_name, parameter_initial, temperature=298.0 * unit.kelvin, platform_name='Reference'): """ Create an example system to be used by other tests """ system, topology = testsystem.system, testsystem.topology integrator = integrators.ExternalPerturbationLangevinIntegrator( splitting="O V R V O", temperature=temperature) # Create the context platform = openmm.Platform.getPlatformByName(platform_name) if platform_name in ['CPU', 'CUDA']: platform.setPropertyDefaultValue('DeterministicForces', 'true') context = openmm.Context(system, integrator, platform) context.setParameter(parameter_name, parameter_initial) context.setPositions(testsystem.positions) context.setVelocitiesToTemperature(temperature) return context, integrator
def __init__(self, alchemical_functions: dict, nsteps_neq: int, timestep: unit.Quantity, temperature: unit.Quantity, work_configuration_save_interval: int = 1, splitting: str = "V R O R V", **kwargs): super(ExternalNonequilibriumSwitchingMove, self).__init__(n_steps=nsteps_neq, **kwargs) self._integrator = integrators.ExternalPerturbationLangevinIntegrator( timestep=timestep, temperature=temperature, splitting=splitting) self._work_configuration_save_interval = work_configuration_save_interval self._alchemical_functions = alchemical_functions self._nsteps_neq = nsteps_neq if nsteps_neq % work_configuration_save_interval != 0: raise ValueError( "Please use a saving interval that is a divisor of the total number of steps" ) #self._number_of_step_moves = self._nsteps_neq // self._work_configuration_save_interval self._cumulative_work = np.zeros([self._nsteps_neq + 1]) self._current_protocol_work = 0.0
nonbondedMethod=app.PME, cutoff=10 * unit.angstrom, ewaldErrorTolerance=1E-4) wbox.system.addForce(openmm.MonteCarloBarostat(pressure, temperature)) # Create the compound integrator langevin = integrators.LangevinIntegrator(splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator( splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) integrator = openmm.CompoundIntegrator() integrator.addIntegrator(langevin) integrator.addIntegrator(ncmc_langevin) # Create context if args.platform == 'CUDA': platform = openmm.Platform.getPlatformByName('CUDA') platform.setPropertyDefaultValue('DeterministicForces', 'true') properties = {'CudaPrecision': 'mixed'} context = openmm.Context(wbox.system, integrator, platform, properties) elif args.platform == 'OpenCL': platform = openmm.Platform.getPlatformByName('OpenCL')
def create_ideal_system(npert=50, nprop=1, deltachem=0.0, platform='CPU'): """ Create small box of water that can impliment ideal mixing with the SaltSwap osmostat. Parameters ---------- npert: int the number of NCMC perturbations nprop: int the number of Langevin propagation steps per NCMC perturbation. deltachem: float the difference in chemical potential between two water molecules and NaCl that has the same nonbonded parameters as two water molecules. platform: str The computational platform. Either 'CPU', 'CUDA', or 'OpenCL'. Returns ------- ncmc_swapper: saltswap.swapper the driver that can perform NCMC exchanges langevin: openmmtools.integrator the integrator for equilibrium sampling. """ # Setting the parameters of the simulation timestep = 2.0 * unit.femtoseconds box_edge = 25.0 * unit.angstrom splitting = 'V R O R V' temperature = 300. * unit.kelvin collision_rate = 1. / unit.picoseconds pressure = 1. * unit.atmospheres # Make the water box test system with a fixed pressure wbox = WaterBox(box_edge=box_edge, model='tip3p', nonbondedMethod=app.PME, cutoff=10 * unit.angstrom, ewaldErrorTolerance=1E-4) wbox.system.addForce(openmm.MonteCarloBarostat(pressure, temperature)) # Create the compound integrator langevin = integrators.LangevinIntegrator(splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator( splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) integrator = openmm.CompoundIntegrator() integrator.addIntegrator(langevin) integrator.addIntegrator(ncmc_langevin) # Create context if platform == 'CUDA': platform = openmm.Platform.getPlatformByName('CUDA') platform.setPropertyDefaultValue('DeterministicForces', 'true') properties = {'CudaPrecision': 'mixed'} context = openmm.Context(wbox.system, integrator, platform, properties) elif platform == 'OpenCL': platform = openmm.Platform.getPlatformByName('OpenCL') properties = {'OpenCLPrecision': 'mixed'} context = openmm.Context(wbox.system, integrator, platform, properties) elif platform == 'CPU': platform = openmm.Platform.getPlatformByName('CPU') context = openmm.Context(wbox.system, integrator, platform) else: raise Exception('Platform name {0} not recognized.'.format( args.platform)) context.setPositions(wbox.positions) context.setVelocitiesToTemperature(temperature) # Create the swapper object for the insertion and deletion of salt ncmc_swapper = Swapper(system=wbox.system, topology=wbox.topology, temperature=temperature, delta_chem=deltachem, ncmc_integrator=ncmc_langevin, pressure=pressure, npert=npert, nprop=nprop) # Set the nonbonded parameters of the ions to be the same as water. This is critical for ideal mixing. ncmc_swapper.cation_parameters = ncmc_swapper.water_parameters ncmc_swapper.anion_parameters = ncmc_swapper.water_parameters ncmc_swapper._set_parampath() return context, ncmc_swapper, langevin
def test_ncmc_update_parameters_in_context(self): """ Testing that the protocol work is correctly calculated in cases when the parameters are updated using context.updateParametersInContext() and the integrator is a compound integrator. The NCMC scheme tested below is based on the one used by the saltswap and protons code-bases. """ from simtk.openmm import app from openmmtools.constants import kB size = 20.0 temperature = 298.0 * unit.kelvin kT = kB * temperature nonbonded_method = 'CutoffPeriodic' platform_name = 'CPU' timestep = 1. * unit.femtoseconds collision_rate = 90. / unit.picoseconds wbox = testsystems.WaterBox(box_edge=size*unit.angstrom, cutoff=9.*unit.angstrom, nonbondedMethod=getattr(app, nonbonded_method)) integrator = integrators.ExternalPerturbationLangevinIntegrator(splitting="V R O R V", temperature=temperature, timestep=timestep, collision_rate=collision_rate) # Create context platform = openmm.Platform.getPlatformByName(platform_name) context = openmm.Context(wbox.system, integrator, platform) context.setPositions(wbox.positions) context.setPositions(wbox.positions) context.setVelocitiesToTemperature(temperature) def switchoff(force, context, frac=0.9): force.setParticleParameters(0, charge=-0.834 * frac, sigma=0.3150752406575124*frac, epsilon=0.635968 * frac) force.setParticleParameters(1, charge=0.417 * frac, sigma=0, epsilon=1 * frac) force.setParticleParameters(2, charge=0.417 * frac, sigma=0, epsilon=1 * frac) force.updateParametersInContext(context) def switchon(force, context): force.setParticleParameters(0, charge=-0.834, sigma=0.3150752406575124, epsilon=0.635968) force.setParticleParameters(1, charge=0.417, sigma=0, epsilon=1) force.setParticleParameters(2, charge=0.417, sigma=0, epsilon=1) force.updateParametersInContext(context) force = wbox.system.getForce(2) # Non-bonded force. # Number of NCMC steps nsteps = 20 niterations = 3 for i in range(niterations): external_protocol_work = 0.0 integrator.reset_protocol_work() integrator.step(1) for step in range(nsteps): fraction = float(step + 1) / float(nsteps) initial_energy = context.getState(getEnergy=True).getPotentialEnergy() switchoff(force, context, frac=fraction) final_energy = context.getState(getEnergy=True).getPotentialEnergy() external_protocol_work += (final_energy - initial_energy) / kT integrator.step(1) integrator_protocol_work = integrator.get_protocol_work(dimensionless=True) assert abs(external_protocol_work - integrator_protocol_work) < 1.E-5 # Return to unperturbed state switchon(force, context)
def create_system(args, splitting): """ Create a test system that's able to run saltswap. Parameters ---------- args: splitting: """ # Fixed simulation parameters temperature = 300.0 * unit.kelvin collision_rate = 1.0 / unit.picoseconds pressure = 1.0 * unit.atmospheres salt_concentration = args.conc * unit.molar # Get the test system and add the barostat. testobj = getattr(testsystems, args.testsystem) testsys = testobj(nonbondedMethod=app.PME, cutoff=10 * unit.angstrom, ewaldErrorTolerance=1E-4, switch_width=1.5 * unit.angstrom) testsys.system.addForce( openmm.MonteCarloBarostat(pressure, temperature)) # Create the compound integrator langevin = integrators.LangevinIntegrator( splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator( splitting=splitting, temperature=temperature, timestep=timestep, collision_rate=collision_rate, measure_shadow_work=False, measure_heat=False) integrator = openmm.CompoundIntegrator() integrator.addIntegrator(langevin) integrator.addIntegrator(ncmc_langevin) # Create context if args.platform == 'CUDA': platform = openmm.Platform.getPlatformByName('CUDA') platform.setPropertyDefaultValue('DeterministicForces', 'true') properties = {'CudaPrecision': 'mixed'} context = openmm.Context(testsys.system, integrator, platform, properties) elif args.platform == 'OpenCL': platform = openmm.Platform.getPlatformByName('OpenCL') properties = {'OpenCLPrecision': 'mixed'} context = openmm.Context(testsys.system, integrator, platform, properties) elif args.platform == 'CPU': platform = openmm.Platform.getPlatformByName('CPU') context = openmm.Context(testsys.system, integrator, platform) else: raise Exception('Platform name {0} not recognized.'.format( args.platform)) context.setPositions(testsys.positions) context.setVelocitiesToTemperature(temperature) # Create the swapper object for the insertion and deletion of salt salinator = wrappers.Salinator(context=context, system=testsys.system, topology=testsys.topology, ncmc_integrator=ncmc_langevin, salt_concentration=salt_concentration, pressure=pressure, temperature=temperature, npert=npert, water_name=args.water_name) # Neutralize the system and initialize the number of salt pairs. salinator.neutralize() salinator.initialize_concentration() return salinator, langevin, integrator