Пример #1
0
def get_integrator(random_seed: int, args: ListOfArgs) -> mm.Integrator:
    """Helper function that returns requested integrator."""
    print("   Integrator initialization...")
    integrator = mm.VerletIntegrator(10 * simtk.unit.femtosecond)  # default integrator
    if args.SIM_RUN_SIMULATION:
        if args.SIM_INTEGRATOR_TYPE == "langevin":
            integrator = mm.LangevinIntegrator(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP)
            integrator.setRandomNumberSeed(random_seed)
        elif args.SIM_INTEGRATOR_TYPE == "brownian":
            print(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP)
            integrator = mm.BrownianIntegrator(args.SIM_TEMP, args.SIM_FRICTION_COEFF, args.SIM_TIME_STEP)
            integrator.setRandomNumberSeed(random_seed)
        elif args.SIM_INTEGRATOR_TYPE == "verlet":
            integrator = mm.VerletIntegrator(args.SIM_TIME_STEP)
    return integrator
Пример #2
0
def production(system, topology, ensemble, temperature, timestep,
        collision_rate,  n_steps, nsteps_out,
        firstframe_name, log_name, traj_name, final_state_name,
        n_equil_steps=1000, ini_positions=None, ini_state_name=None,
        use_switch=False, r_switch=None, pressure=None, minimize=False, 
        cuda=False, gpu_idxs=None, more_reporters=[], dynamics="Langevin", 
        use_platform=None): 

    if use_switch:
        # set switching function on nonbonded forces
        for i in range(system.getNumForces()):
            force = system.getForce(i) 
            if force.__repr__().find("NonbondedForce") > -1:
                force.setUseSwitchingFunction(True)
                if r_switch is None:
                    raise IOError("Need to input r_switch if use_switch = True")
                else:
                    force.setSwitchingDistance(r_switch/unit.nanometer)
            
    if ensemble == "NVE": 
        integrator = omm.VerletIntegrator(timestep)
    else:
        if dynamics == "Langevin":
            integrator = omm.LangevinIntegrator(temperature, collision_rate, timestep)
        elif dynamics == "Brownian":
            integrator = omm.BrownianIntegrator(temperature, collision_rate, timestep)
        else:
            raise IOError("dynamics must be Langevin or Brownian")
        if ensemble == "NPT":
            if pressure is None:
                raise ValueError("If ensemble is NPT need to specficy pressure")
            system.addForce(omm.MonteCarloBarostat(pressure, temperature))
    
    if not use_platform is None:
        if use_platform == "CUDA":
            platform = omm.Platform.getPlatformByName('CUDA') 
            if gpu_idxs is None:
                properties = {'DeviceIndex': '0'}
            else:
                properties = {'DeviceIndex': gpu_idxs}

            simulation = app.Simulation(topology, system, integrator, platform, properties)
        elif use_platform == "CPU":
            platform = omm.Platform.getPlatformByName("CPU")
            simulation = app.Simulation(topology, system, integrator, platform)
        else:
            raise ValueError("use_platform needs to be CUDA or CPU or not specfied")
    else:
        simulation = app.Simulation(topology, system, integrator)


    if not ini_positions is None:
        # set initial positions and box dimensions
        simulation.context.setPositions(ini_positions)
        #simulation.context.setPeriodicBoxVectors()
    elif not ini_position_file is None:
        simulation.loadState(ini_state_name)
    else:
        raise ValueError("Need to specify initial positions somehow!")

    if minimize:
        simulation.minimizeEnergy(tolerance=energy_minimization_tol)

    # initial equilibration
    simulation.step(n_equil_steps)

    # save the first frame minimized
    simulation.reporters.append(app.PDBReporter(firstframe_name, 1))
    simulation.step(1)
    simulation.reporters.pop(0)

    # record coordinates
    simulation.reporters.append(app.DCDReporter(traj_name, nsteps_out))
    simulation.reporters.append(app.StateDataReporter(log_name, nsteps_out,
        step=True, potentialEnergy=True, kineticEnergy=True, temperature=True,
        density=True, volume=True))

    # add user-defined reporters for e.g. forces or velocities
    if len(more_reporters) > 0:
        for i in range(len(more_reporters)):
            simulation.reporters.append(more_reporters[i])

    # run simulation!
    simulation.step(n_steps)

    # save final state. positions, box vectors. 
    simulation.saveState(final_state_name)
Пример #3
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, string_types):
            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() == "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)