def test_short_simulation(tmp_path): system, pars = get_system('uio66') configuration = Configuration(system, pars) # conversion conversion = ExplicitConversion() openmm_seed = conversion.apply(configuration) system = openmm_seed.get_system() # necessary to create Simulation object topology, positions = configuration.create_topology() a, b, c = topology.getPeriodicBoxVectors() # instantiate simulation for each platform platforms = ['Reference', 'CPU', 'CUDA', 'OpenCL'] for name in platforms: integrator = mm.LangevinMiddleIntegrator( 300 * unit.kelvin, # temperature 0.1 * unit.picosecond, # friction coefficient 0.5 * unit.femtosecond, # step size ) try: platform = mm.Platform.getPlatformByName(name) except mm.OpenMMException: continue simulation = mm.app.Simulation( topology, system, integrator, platform, ) simulation.context.setPositions(positions) #simulation.context.setPeriodicBoxVectors(box[0], box[1], box[2]) simulation.context.setPeriodicBoxVectors(a, b, c) simulation.step(20)
def runOneTest(testName, options): """Perform a single benchmarking simulation.""" explicit = (testName in ('rf', 'pme', 'amoebapme')) amoeba = (testName in ('amoebagk', 'amoebapme')) apoa1 = testName.startswith('apoa1') hydrogenMass = None print() if amoeba: print('Test: %s (epsilon=%g)' % (testName, options.epsilon)) elif testName == 'pme': print('Test: pme (cutoff=%g)' % options.cutoff) else: print('Test: %s' % testName) platform = mm.Platform.getPlatformByName(options.platform) # Create the System. if amoeba: constraints = None epsilon = float(options.epsilon) if explicit: ff = app.ForceField('amoeba2009.xml') pdb = app.PDBFile('5dfr_solv-cube_equil.pdb') cutoff = 0.7 * unit.nanometers vdwCutoff = 0.9 * unit.nanometers system = ff.createSystem(pdb.topology, nonbondedMethod=app.PME, nonbondedCutoff=cutoff, vdwCutoff=vdwCutoff, constraints=constraints, ewaldErrorTolerance=0.00075, mutualInducedTargetEpsilon=epsilon, polarization=options.polarization) else: ff = app.ForceField('amoeba2009.xml', 'amoeba2009_gk.xml') pdb = app.PDBFile('5dfr_minimized.pdb') cutoff = 2.0 * unit.nanometers vdwCutoff = 1.2 * unit.nanometers system = ff.createSystem(pdb.topology, nonbondedMethod=app.NoCutoff, constraints=constraints, mutualInducedTargetEpsilon=epsilon, polarization=options.polarization) for f in system.getForces(): if isinstance(f, mm.AmoebaMultipoleForce) or isinstance( f, mm.AmoebaVdwForce) or isinstance( f, mm.AmoebaGeneralizedKirkwoodForce) or isinstance( f, mm.AmoebaWcaDispersionForce): f.setForceGroup(1) dt = 0.002 * unit.picoseconds integ = mm.MTSIntegrator(dt, [(0, 2), (1, 1)]) else: if apoa1: ff = app.ForceField('amber14/protein.ff14SB.xml', 'amber14/lipid17.xml', 'amber14/tip3p.xml') pdb = app.PDBFile('apoa1.pdb') if testName == 'apoa1pme': method = app.PME cutoff = options.cutoff elif testName == 'apoa1ljpme': method = app.LJPME cutoff = options.cutoff else: method = app.CutoffPeriodic cutoff = 1 * unit.nanometers friction = 1 * (1 / unit.picoseconds) hydrogenMass = 1.5 * unit.amu elif explicit: ff = app.ForceField('amber99sb.xml', 'tip3p.xml') pdb = app.PDBFile('5dfr_solv-cube_equil.pdb') if testName == 'pme': method = app.PME cutoff = options.cutoff else: method = app.CutoffPeriodic cutoff = 1 * unit.nanometers friction = 1 * (1 / unit.picoseconds) else: ff = app.ForceField('amber99sb.xml', 'amber99_obc.xml') pdb = app.PDBFile('5dfr_minimized.pdb') method = app.CutoffNonPeriodic cutoff = 2 * unit.nanometers friction = 91 * (1 / unit.picoseconds) if options.heavy: dt = 0.005 * unit.picoseconds constraints = app.AllBonds hydrogenMass = 4 * unit.amu integ = mm.LangevinIntegrator(300 * unit.kelvin, friction, dt) else: dt = 0.004 * unit.picoseconds constraints = app.HBonds integ = mm.LangevinMiddleIntegrator(300 * unit.kelvin, friction, dt) system = ff.createSystem(pdb.topology, nonbondedMethod=method, nonbondedCutoff=cutoff, constraints=constraints, hydrogenMass=hydrogenMass) print('Step Size: %g fs' % dt.value_in_unit(unit.femtoseconds)) properties = {} initialSteps = 5 if options.device is not None and platform.getName() in ('CUDA', 'OpenCL'): properties['DeviceIndex'] = options.device if ',' in options.device or ' ' in options.device: initialSteps = 250 if options.precision is not None and platform.getName() in ('CUDA', 'OpenCL'): properties['Precision'] = options.precision # Run the simulation. integ.setConstraintTolerance(1e-5) if len(properties) > 0: context = mm.Context(system, integ, platform, properties) else: context = mm.Context(system, integ, platform) context.setPositions(pdb.positions) context.setVelocitiesToTemperature(300 * unit.kelvin) steps = 20 while True: time = timeIntegration(context, steps, initialSteps) if time >= 0.5 * options.seconds: break if time < 0.5: steps = int( steps * 1.0 / time ) # Integrate enough steps to get a reasonable estimate for how many we'll need. else: steps = int(steps * options.seconds / time) print('Integrated %d steps in %g seconds' % (steps, time)) print('%g ns/day' % (dt * steps * 86400 / time).value_in_unit(unit.nanoseconds))
def runOneTest(testName, options): """Perform a single benchmarking simulation.""" explicit = (testName not in ('gbsa', 'amoebagk')) amoeba = (testName in ('amoebagk', 'amoebapme')) apoa1 = testName.startswith('apoa1') amber = (testName.startswith('amber')) hydrogenMass = None print() if amoeba: print('Test: %s (epsilon=%g)' % (testName, options.epsilon)) elif testName == 'pme': print('Test: pme (cutoff=%g)' % options.cutoff) else: print('Test: %s' % testName) print('Ensemble: %s' % options.ensemble) platform = mm.Platform.getPlatformByName(options.platform) # Create the System. temperature = 300 * unit.kelvin if explicit: friction = 1 * (1 / unit.picoseconds) else: friction = 91 * (1 / unit.picoseconds) if amoeba: constraints = None epsilon = float(options.epsilon) if explicit: ff = app.ForceField('amoeba2009.xml') pdb = app.PDBFile('5dfr_solv-cube_equil.pdb') cutoff = 0.7 * unit.nanometers vdwCutoff = 0.9 * unit.nanometers system = ff.createSystem(pdb.topology, nonbondedMethod=app.PME, nonbondedCutoff=cutoff, vdwCutoff=vdwCutoff, constraints=constraints, ewaldErrorTolerance=0.00075, mutualInducedTargetEpsilon=epsilon, polarization=options.polarization) else: ff = app.ForceField('amoeba2009.xml', 'amoeba2009_gk.xml') pdb = app.PDBFile('5dfr_minimized.pdb') cutoff = 2.0 * unit.nanometers vdwCutoff = 1.2 * unit.nanometers system = ff.createSystem(pdb.topology, nonbondedMethod=app.NoCutoff, constraints=constraints, mutualInducedTargetEpsilon=epsilon, polarization=options.polarization) for f in system.getForces(): if isinstance(f, mm.AmoebaMultipoleForce) or isinstance( f, mm.AmoebaVdwForce) or isinstance( f, mm.AmoebaGeneralizedKirkwoodForce) or isinstance( f, mm.AmoebaWcaDispersionForce): f.setForceGroup(1) dt = 0.002 * unit.picoseconds if options.ensemble == 'NVE': integ = mm.MTSIntegrator(dt, [(0, 2), (1, 1)]) else: integ = mm.MTSLangevinIntegrator(temperature, friction, dt, [(0, 2), (1, 1)]) positions = pdb.positions elif amber: dirname = downloadAmberSuite() names = { 'amber20-dhfr': 'JAC', 'amber20-factorix': 'FactorIX', 'amber20-cellulose': 'Cellulose', 'amber20-stmv': 'STMV' } fileName = names[testName] prmtop = app.AmberPrmtopFile( os.path.join(dirname, f'PME/Topologies/{fileName}.prmtop')) inpcrd = app.AmberInpcrdFile( os.path.join(dirname, f'PME/Coordinates/{fileName}.inpcrd')) topology = prmtop.topology positions = inpcrd.positions dt = 0.004 * unit.picoseconds method = app.PME cutoff = options.cutoff constraints = app.HBonds system = prmtop.createSystem(nonbondedMethod=method, nonbondedCutoff=cutoff, constraints=constraints) if options.ensemble == 'NVE': integ = mm.VerletIntegrator(dt) else: integ = mm.LangevinMiddleIntegrator(temperature, friction, dt) else: if apoa1: ff = app.ForceField('amber14/protein.ff14SB.xml', 'amber14/lipid17.xml', 'amber14/tip3p.xml') pdb = app.PDBFile('apoa1.pdb') if testName == 'apoa1pme': method = app.PME cutoff = options.cutoff elif testName == 'apoa1ljpme': method = app.LJPME cutoff = options.cutoff else: method = app.CutoffPeriodic cutoff = 1 * unit.nanometers hydrogenMass = 1.5 * unit.amu elif explicit: ff = app.ForceField('amber99sb.xml', 'tip3p.xml') pdb = app.PDBFile('5dfr_solv-cube_equil.pdb') if testName == 'pme': method = app.PME cutoff = options.cutoff else: method = app.CutoffPeriodic cutoff = 1 * unit.nanometers else: ff = app.ForceField('amber99sb.xml', 'amber99_obc.xml') pdb = app.PDBFile('5dfr_minimized.pdb') method = app.CutoffNonPeriodic cutoff = 2 * unit.nanometers if options.heavy: dt = 0.005 * unit.picoseconds constraints = app.AllBonds hydrogenMass = 4 * unit.amu if options.ensemble == 'NVE': integ = mm.VerletIntegrator(dt) else: integ = mm.LangevinIntegrator(temperature, friction, dt) else: dt = 0.004 * unit.picoseconds constraints = app.HBonds if options.ensemble == 'NVE': integ = mm.VerletIntegrator(dt) else: integ = mm.LangevinMiddleIntegrator(temperature, friction, dt) positions = pdb.positions system = ff.createSystem(pdb.topology, nonbondedMethod=method, nonbondedCutoff=cutoff, constraints=constraints, hydrogenMass=hydrogenMass) if options.ensemble == 'NPT': system.addForce(mm.MonteCarloBarostat(1 * unit.bar, temperature, 100)) print('Step Size: %g fs' % dt.value_in_unit(unit.femtoseconds)) properties = {} initialSteps = 5 if options.device is not None and platform.getName() in ('CUDA', 'OpenCL'): properties['DeviceIndex'] = options.device if ',' in options.device or ' ' in options.device: initialSteps = 250 if options.precision is not None and platform.getName() in ('CUDA', 'OpenCL'): properties['Precision'] = options.precision # Run the simulation. integ.setConstraintTolerance(1e-5) if len(properties) > 0: context = mm.Context(system, integ, platform, properties) else: context = mm.Context(system, integ, platform) context.setPositions(positions) if amber: if inpcrd.boxVectors is not None: context.setPeriodicBoxVectors(*inpcrd.boxVectors) mm.LocalEnergyMinimizer.minimize( context, 100 * unit.kilojoules_per_mole / unit.nanometer) context.setVelocitiesToTemperature(temperature) steps = 20 while True: time = timeIntegration(context, steps, initialSteps) if time >= 0.5 * options.seconds: break if time < 0.5: steps = int( steps * 1.0 / time ) # Integrate enough steps to get a reasonable estimate for how many we'll need. else: steps = int(steps * options.seconds / time) print('Integrated %d steps in %g seconds' % (steps, time)) print('%g ns/day' % (dt * steps * 86400 / time).value_in_unit(unit.nanoseconds))
def __init__(self, **kwargs): """ All numbers here are floats. Units specified in a parameter. Parameters ---------- N : int number of particles error_tol : float, optional Error tolerance parameter for variableLangevin integrator Values of around 0.01 are reasonable for a "nice" simulation (i.e. simulation with soft forces etc). Simulations with strong forces may need 0.001 or less OpenMM manual recommends 0.001, but our forces tend to be "softer" than theirs timestep : number timestep in femtoseconds. Mandatory for non-variable integrators. Ignored for variableLangevin integrator. Value of 70-80 are appropriate collision_rate : number collision rate in inverse picoseconds. values of 0.01 or 0.05 are often used. Consult with lab members on values. In brief, equilibrium simulations likely do not care about the exact dynamics you're using, and therefore can be simulated in a "ballistic" dynamics with col_rate of around 0.001-0.01. Dynamical simulations and active simulations may be more sensitive to col_rate, though this is still under discussion/investigation. Johannes converged on using 0.1 for loop extrusion simulations, just to be safe. PBCbox : (float,float,float) or False; default:False Controls periodic boundary conditions If PBCbox is False, do not use periodic boundary conditions If intending to use PBC, then set PBCbox to (x,y,z) where x,y,z are dimensions of the bounding box for PBC GPU : GPU index as a string ("0" for first, "1" for second etc.) Machines with 1 GPU automatically select their GPU. integrator : "langevin", "variableLangevin", "verlet", "variableVerlet", "brownian", optional Integrator to use (see Openmm class reference) mass : number or np.array Particle mass (default 100 amu) temperature : simtk.units.quantity(units.kelvin), optional Temperature of the simulation. Devault value is 300 K. verbose : bool, optional If True, prints a lot of stuff in the command line. length_scale : float, optional The geometric scaling factor of the system. By default, length_scale=1.0 and harmonic bonds and repulsive forces have the scale of 1 nm. max_Ek: float, optional raise error if kinetic energy in (kT/particle) exceeds this value platform : string, optional Platform to use: CUDA (preferred fast GPU platform) OpenCL (maybe slower GPU platofrm, does not need CUDA installed) CPU (medium speed parallelized CPU platform) reference (slow CPU platform for debug) verbose : bool, optional Shout out loud about every change. precision: str, optional (not recommended to change) mixed is optimal for most situations. If you are using double precision, it will be slower by a factor of 10 or so. save_decimals: int or False, optional Round to this number of decimals before saving. ``False`` is no rounding. Default is 2. It gives maximum error of 0.005, which is nearly always harmless but saves up to 40% of storage space (0.6 of the original) Using one decimal is safe most of the time, and reduces storage to 40% of int32. NOTE that using periodic boundary conditions will make storage advantage less. """ default_args = { "platform": "CUDA", "GPU": "0", "integrator": "variablelangevin", "temperature": 300, "PBCbox": False, "length_scale": 1.0, "mass": 100, "reporters": [], "max_Ek": 10, "precision": "mixed", "save_decimals": 2, "verbose": False, } valid_names = list(default_args.keys()) + [ "N", "error_tol", "collision_rate", "timestep", ] for i in kwargs.keys(): if i not in valid_names: raise ValueError( "incorrect argument provided: {0}. Allowed are {1}".format( i, valid_names)) if None in kwargs.values(): raise ValueError( "None is not allowed in arguments due to HDF5 incompatiliblity. Use False instead." ) default_args.update(kwargs) kwargs = default_args self.kwargs = kwargs platform = kwargs["platform"] self.GPU = kwargs["GPU"] # setting default GPU properties = {} if self.GPU.lower() != "default": if platform.lower() in ["cuda", "opencl"]: properties["DeviceIndex"] = str(self.GPU) properties["Precision"] = kwargs["precision"] self.properties = properties if platform.lower() == "opencl": platform_object = openmm.Platform.getPlatformByName("OpenCL") elif platform.lower() == "reference": platform_object = openmm.Platform.getPlatformByName("Reference") elif platform.lower() == "cuda": platform_object = openmm.Platform.getPlatformByName("CUDA") elif platform.lower() == "cpu": platform_object = openmm.Platform.getPlatformByName("CPU") else: raise RuntimeError("Undefined platform: {0}".format(platform)) self.platform = platform_object self.temperature = kwargs["temperature"] self.collisionRate = kwargs["collision_rate"] * (1 / simtk.unit.picosecond) self.integrator_type = kwargs["integrator"] if isinstance(self.integrator_type, str): self.integrator_type = str(self.integrator_type) if self.integrator_type.lower() == "langevin": self.integrator = openmm.LangevinIntegrator( self.temperature, kwargs["collision_rate"] * (1 / simtk.unit.picosecond), kwargs["timestep"] * simtk.unit.femtosecond, ) elif self.integrator_type.lower() == "variablelangevin": self.integrator = openmm.VariableLangevinIntegrator( self.temperature, kwargs["collision_rate"] * (1 / simtk.unit.picosecond), kwargs["error_tol"], ) elif self.integrator_type.lower() == "langevinmiddle": self.integrator = openmm.LangevinMiddleIntegrator( self.temperature, kwargs["collision_rate"] * (1 / simtk.unit.picosecond), kwargs["timestep"] * simtk.unit.femtosecond, ) elif self.integrator_type.lower() == "verlet": self.integrator = openmm.VariableVerletIntegrator( kwargs["timestep"] * simtk.unit.femtosecond) elif self.integrator_type.lower() == "variableverlet": self.integrator = openmm.VariableVerletIntegrator( kwargs["error_tol"]) elif self.integrator_type.lower() == "brownian": self.integrator = openmm.BrownianIntegrator( self.temperature, kwargs["collision_rate"] * (1 / simtk.unit.picosecond), kwargs["timestep"] * simtk.unit.femtosecond, ) else: logging.info("Using the provided integrator object") self.integrator = self.integrator_type self.integrator_type = "UserDefined" kwargs["integrator"] = "user_defined" self.N = kwargs["N"] self.verbose = kwargs["verbose"] self.reporters = kwargs["reporters"] self.forces_applied = False self.length_scale = kwargs["length_scale"] self.eK_critical = kwargs["max_Ek"] # Max allowed kinetic energy self.step = 0 self.block = 0 self.time = 0 self.nm = simtk.unit.nanometer self.kB = simtk.unit.BOLTZMANN_CONSTANT_kB * simtk.unit.AVOGADRO_CONSTANT_NA self.kT = self.kB * self.temperature * simtk.unit.kelvin # thermal energy # All masses are the same, # unless individual mass multipliers are specified in self.load() self.conlen = 1.0 * simtk.unit.nanometer * self.length_scale self.kbondScalingFactor = float( (2 * self.kT / self.conlen**2) / (simtk.unit.kilojoule_per_mole / simtk.unit.nanometer**2)) self.system = openmm.System() # adding PBC self.PBC = False if kwargs["PBCbox"] is not False: self.PBC = True PBCbox = np.array(kwargs["PBCbox"]) self.system.setDefaultPeriodicBoxVectors( [float(PBCbox[0]), 0.0, 0.0], [0.0, float(PBCbox[1]), 0.0], [0.0, 0.0, float(PBCbox[2])], ) self.force_dict = {} # Dictionary to store forces # saving arguments - not trying to save reporters because they are not serializable kwCopy = {i: j for i, j in kwargs.items() if i != "reporters"} for reporter in self.reporters: reporter.report("initArgs", kwCopy)