Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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))
Ejemplo n.º 3
0
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))
Ejemplo n.º 4
0
    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)