Пример #1
0
    def _propagate_replicas(self):
        # Reset statistics for MC trial times.
        self.displacement_trial_time = 0.0
        self.rotation_trial_time = 0.0
        self.displacement_trials_accepted = 0
        self.rotation_trials_accepted = 0

        # Propagate replicas.
        ReplicaExchange._propagate_replicas(self)

        # Print summary statistics.
        # TODO: Streamline this idiom.
        if self.mpicomm:
            # MPI
            from mpi4py import MPI
            if self.mc_displacement and (self.mc_atoms is not None):
                self.displacement_trials_accepted = self.mpicomm.reduce(self.displacement_trials_accepted, op=MPI.SUM)
                self.displacement_trial_time = self.mpicomm.reduce(self.displacement_trial_time, op=MPI.SUM)
                if self.mpicomm.rank == 0:
                    logger.debug("Displacement MC trial times consumed %.3f s aggregate (%d accepted)" % (self.displacement_trial_time, self.displacement_trials_accepted))

            if self.mc_rotation and (self.mc_atoms is not None):
                self.rotation_trials_accepted = self.mpicomm.reduce(self.rotation_trials_accepted, op=MPI.SUM)
                self.rotation_trial_time = self.mpicomm.reduce(self.rotation_trial_time, op=MPI.SUM)
                if self.mpicomm.rank == 0:
                    logger.debug("Rotation MC trial times consumed %.3f s aggregate (%d accepted)" % (self.rotation_trial_time, self.rotation_trials_accepted))
        else:
            # SERIAL
            if self.mc_displacement and (self.mc_atoms is not None):
                logger.debug("Displacement MC trial times consumed %.3f s aggregate (%d accepted)" % (self.displacement_trial_time, self.displacement_trials_accepted))
            if self.mc_rotation and (self.mc_atoms is not None):
                logger.debug("Rotation MC trial times consumed %.3f s aggregate (%d accepted)" % (self.rotation_trial_time, self.rotation_trials_accepted))

        return
Пример #2
0
    def resume(self, options=None):
        """
        """
        ReplicaExchange.resume(self, options=options)

        #
        # Cache Context and integrator.
        #

        # Use first state as reference state.
        state = self.states[0]

        # If temperature and pressure are specified, make sure MonteCarloBarostat is attached.
        if state.temperature and state.pressure:
            forces = { state.system.getForce(index).__class__.__name__ : state.system.getForce(index) for index in range(state.system.getNumForces()) }

            if 'MonteCarloAnisotropicBarostat' in forces:
                raise Exception('MonteCarloAnisotropicBarostat is unsupported.')

            if 'MonteCarloBarostat' in forces:
                barostat = forces['MonteCarloBarostat']
                # Set temperature and pressure.
                barostat.setTemperature(state.temperature)
                barostat.setDefaultPressure(state.pressure)
                barostat.setRandomNumberSeed(int(np.random.randint(0, MAX_SEED)))
            else:
                # Create barostat and add it to the system if it doesn't have one already.
                barostat = openmm.MonteCarloBarostat(state.pressure, state.temperature)
                barostat.setRandomNumberSeed(int(np.random.randint(0, MAX_SEED)))
                state.system.addForce(barostat)
Пример #3
0
    def _display_citations(self):
        ReplicaExchange._display_citations(self)

        yank_citations = """\
        Chodera JD, Shirts MR, Wang K, Friedrichs MS, Eastman P, Pande VS, and Branson K. YANK: An extensible platform for GPU-accelerated free energy calculations. In preparation."""

        print yank_citations
        print ""

        return
Пример #4
0
    def _display_citations(self):
        ReplicaExchange._display_citations(self)

        yank_citations = """\
        Chodera JD, Shirts MR, Wang K, Friedrichs MS, Eastman P, Pande VS, and Branson K. YANK: An extensible platform for GPU-accelerated free energy calculations. In preparation."""

        print yank_citations
        print ""

        return
Пример #5
0
    def _finalize(self):
        """
        Do anything necessary to finish run except close files.

        """
        ReplicaExchange._finalize(self)

        # Clean up cached context and integrator.
        if hasattr(self, 'context'):
            del self._context, self._integrator

        return
Пример #6
0
    def _finalize(self):
        """
        Do anything necessary to finish run except close files.

        """
        ReplicaExchange._finalize(self)

        # Clean up cached context and integrator.
        if hasattr(self, 'context'):
            del self._context, self._integrator

        return
Пример #7
0
    def create(self,
               reference_state,
               alchemical_states,
               positions,
               displacement_sigma=None,
               mc_atoms=None,
               options=None,
               metadata=None):
        """
        Initialize a modified Hamiltonian exchange simulation object.

        Parameters
        ----------
        reference_state : ThermodynamicState
           reference state containing all thermodynamic parameters and reference System object'
        alchemical_states : list of AlchemicalState
           list of alchemical states (one per replica)
        positions : simtk.unit.Quantity of numpy natoms x 3 with units length
           positions (or a list of positions objects) for initial assignment of replicas (will be used in round-robin assignment)
        displacement_sigma : simtk.unit.Quantity with units distance
           size of displacement trial for Monte Carlo displacements, if specified (default: 1 nm)
        ligand_atoms : list of int, optional, default=None
           atoms to use for trial displacements for translational and orientational Monte Carlo trials, if specified (all atoms if None)
        options : dict, optional, default=None
           Optional dict to use for specifying simulation options. Provided keywords will be matched to object variables to replace defaults.
        metadata : dict, optional, default=None
           metadata to store in a 'metadata' group in store file

        """

        # If an empty set is specified for mc_atoms, set this to None.
        if mc_atoms is not None:
            if len(mc_atoms) == 0:
                mc_atoms = None

        # Store trial displacement magnitude and atoms to rotate in MC move.
        self.displacement_sigma = 1.0 * unit.nanometer
        if mc_atoms is not None:
            self.mc_atoms = np.array(mc_atoms)
            self.mc_displacement = True
            self.mc_rotation = True
        else:
            self.mc_atoms = None
            self.mc_displacement = False
            self.mc_rotation = False

        self.displacement_trials_accepted = 0  # number of MC displacement trials accepted
        self.rotation_trials_accepted = 0  # number of MC displacement trials accepted

        # Store reference system.
        self.reference_system = copy.deepcopy(reference_state.system)

        # TODO: Form metadata dict.

        # Initialize replica-exchange simlulation.
        states = list()
        for alchemical_state in alchemical_states:
            state = ThermodynamicState(system=self.reference_system,
                                       temperature=reference_state.temperature,
                                       pressure=reference_state.pressure)
            setattr(state, 'alchemical_state',
                    copy.deepcopy(alchemical_state))  # attach alchemical state
            states.append(state)

        # Initialize replica-exchange simlulation.
        ReplicaExchange.create(self,
                               states,
                               positions,
                               options=options,
                               metadata=metadata)

        # Override title.
        self.title = 'Alchemical Hamiltonian exchange simulation created using HamiltonianExchange class of repex.py on %s' % time.asctime(
            time.localtime())

        return
Пример #8
0
    def create(self, reference_state, alchemical_states, positions, displacement_sigma=None, mc_atoms=None, options=None, metadata=None):
        """
        Initialize a modified Hamiltonian exchange simulation object.

        Parameters
        ----------
        reference_state : ThermodynamicState
           reference state containing all thermodynamic parameters and reference System object'
        alchemical_states : list of AlchemicalState
           list of alchemical states (one per replica)
        positions : simtk.unit.Quantity of numpy natoms x 3 with units length
           positions (or a list of positions objects) for initial assignment of replicas (will be used in round-robin assignment)
        displacement_sigma : simtk.unit.Quantity with units distance
           size of displacement trial for Monte Carlo displacements, if specified (default: 1 nm)
        ligand_atoms : list of int, optional, default=None
           atoms to use for trial displacements for translational and orientational Monte Carlo trials, if specified (all atoms if None)
        options : dict, optional, default=None
           Optional dict to use for specifying simulation options. Provided keywords will be matched to object variables to replace defaults.
        metadata : dict, optional, default=None
           metadata to store in a 'metadata' group in store file

        """

        # If an empty set is specified for mc_atoms, set this to None.
        if mc_atoms is not None:
            if len(mc_atoms) == 0:
                mc_atoms = None

        # Store trial displacement magnitude and atoms to rotate in MC move.
        self.displacement_sigma = 1.0 * unit.nanometer
        if mc_atoms is not None:
            self.mc_atoms = np.array(mc_atoms)
            self.mc_displacement = True
            self.mc_rotation = True
        else:
            self.mc_atoms = None
            self.mc_displacement = False
            self.mc_rotation = False

        self.displacement_trials_accepted = 0 # number of MC displacement trials accepted
        self.rotation_trials_accepted = 0 # number of MC displacement trials accepted

        # Store reference system.
        self.reference_system = copy.deepcopy(reference_state.system)

        # TODO: Form metadata dict.

        # Initialize replica-exchange simlulation.
        states = list()
        for alchemical_state in alchemical_states:
            state = ThermodynamicState(system=self.reference_system, temperature=reference_state.temperature, pressure=reference_state.pressure)
            setattr(state, 'alchemical_state', copy.deepcopy(alchemical_state)) # attach alchemical state
            states.append(state)

        # Initialize replica-exchange simlulation.
        ReplicaExchange.create(self, states, positions, options=options, metadata=metadata)

        # Override title.
        self.title = 'Alchemical Hamiltonian exchange simulation created using HamiltonianExchange class of repex.py on %s' % time.asctime(time.localtime())

        return
Пример #9
0
    def __init__(self,
                 temperature,
                 nbins,
                 store_filename,
                 protocol=None,
                 mm=None):
        """
        Initialize a Hamiltonian exchange simulation object.

        ARGUMENTS

        store_filename (string) - name of NetCDF file to bind to for simulation output and checkpointing

        OPTIONAL ARGUMENTS

        protocol (dict) - Optional protocol to use for specifying simulation protocol as a dict. Provided keywords will be matched to object variables to replace defaults.

        NOTES

        von Mises distribution used for restraints

        http://en.wikipedia.org/wiki/Von_Mises_distribution

        """

        import simtk.pyopenmm.extras.testsystems as testsystems

        # Create reference system and state.
        [system, coordinates] = testsystems.AlanineDipeptideImplicit()
        self.reference_system = system
        self.reference_state = repex.ThermodynamicState(
            system=system, temperature=temperature)

        self.nbins = nbins
        self.kT = (repex.kB * temperature)
        self.beta = 1.0 / self.kT

        self.delta = 360.0 / float(
            nbins) * units.degrees  # bin spacing (angular)
        self.sigma = self.delta / 3.0  # standard deviation (angular)
        self.kappa = (self.sigma / units.radians)**(
            -2)  # kappa parameter (unitless)

        # Create list of thermodynamic states with different bias potentials.
        states = list()
        # Create a state without a biasing potential.
        [system, coordinates] = testsystems.AlanineDipeptideImplicit()
        state = repex.ThermodynamicState(system=system,
                                         temperature=temperature)
        states.append(state)
        # Create states with biasing potentials.
        for phi_index in range(nbins):
            for psi_index in range(nbins):
                print "bin (%d,%d)" % (phi_index, psi_index)
                # Create system.
                [system, coordinates] = testsystems.AlanineDipeptideImplicit()
                # Add biasing potentials.
                phi0 = (float(phi_index) +
                        0.5) * self.delta - 180.0 * units.degrees
                psi0 = (float(psi_index) +
                        0.5) * self.delta - 180.0 * units.degrees
                force = openmm.CustomTorsionForce(
                    '-kT * kappa * cos(theta - theta0)')
                force.addGlobalParameter('kT',
                                         self.kT / units.kilojoules_per_mole)
                force.addPerTorsionParameter('kappa')
                force.addPerTorsionParameter('theta0')
                force.addTorsion(4, 6, 8, 14,
                                 [self.kappa, phi0 / units.radians])
                force.addTorsion(6, 8, 14, 16,
                                 [self.kappa, psi0 / units.radians])
                system.addForce(force)
                # Add state.
                state = repex.ThermodynamicState(system=system,
                                                 temperature=temperature)
                states.append(state)

        # Initialize replica-exchange simlulation.
        ReplicaExchange.__init__(self,
                                 states,
                                 coordinates,
                                 store_filename,
                                 protocol=protocol,
                                 mm=mm)

        # Override title.
        self.title = '2D umbrella sampling replica-exchange simulation created on %s' % time.asctime(
            time.localtime())

        return
Пример #10
0
def test_velocity_assignment(mpicomm=None, verbose=True):
    """
    Test Maxwell-Boltzmann velocity assignment subtroutine produces correct distribution, raising an exception if this test fails.

    """

    # Stop here if not root node.
    if mpicomm and (mpicomm.rank != 0): return

    if verbose: print "Testing Maxwell-Boltzmann velocity assignment: ",

    # Make a list of all test system constructors.
    import testsystems

    # Test parameters
    temperature = 298.0 * units.kelvin # test temperature
    kT = kB * temperature # thermal energy
    ntrials = 1000 # number of test trials
    systems_to_test = ['HarmonicOscillator', 'HarmonicOscillatorArray', 'AlanineDipeptideImplicit'] # systems to test
    
    for system_name in systems_to_test:
        #print '*' * 80
        #print system_name
   
        # Create system.
        constructor = getattr(testsystems, system_name)
        [system, coordinates] = constructor()

        # Create temporary filename.
        import tempfile # use a temporary file for testing
        file = tempfile.NamedTemporaryFile() 
        store_filename = file.name

        # Create repex instance.
        from repex import ReplicaExchange
        from thermodynamics import ThermodynamicState
        states = [ ThermodynamicState(system, temperature=temperature) ]
        simulation = ReplicaExchange(states=states, coordinates=coordinates, store_filename=store_filename)

        # Create integrator and context.
        natoms = system.getNumParticles()

        velocity_trials = numpy.zeros([ntrials, natoms, 3])
        kinetic_energy_trials = numpy.zeros([ntrials])

        for trial in range(ntrials):
            velocities = simulation._assign_Maxwell_Boltzmann_velocities(system, temperature)  
            kinetic_energy = 0.5 * units.sum(units.sum(system.masses * velocities**2)) 
            velocity_trials[trial,:,:] = velocities / (units.nanometers / units.picosecond)
            kinetic_energy_trials[trial] = kinetic_energy / units.kilocalories_per_mole
            
        velocity_mean = velocity_trials.mean(0)
        velocity_stderr = velocity_trials.std(0) / numpy.sqrt(ntrials)

        kinetic_analytical = (3.0/2.0) * natoms * kT / units.kilocalories_per_mole
        kinetic_mean = kinetic_energy_trials.mean()
        kinetic_error = kinetic_mean - kinetic_analytical
        kinetic_stderr = kinetic_energy_trials.std() / numpy.sqrt(ntrials)

        # Test if violations exceed tolerance.
        MAX_SIGMA = 6.0 # maximum number of standard errors allowed
        if numpy.any(numpy.abs(kinetic_error / kinetic_stderr) > MAX_SIGMA):
            print "analytical kinetic energy"
            print kinetic_analytical
            print "mean kinetic energy (kcal/mol)"
            print kinetic_mean
            print "difference (kcal/mol)"
            print kinetic_mean - kinetic_analytical
            print "stderr (kcal/mol)"
            print kinetic_stderr
            print "nsigma"
            print (kinetic_mean - kinetic_analytical) / kinetic_stderr
            raise Exception("Mean kinetic energy exceeds error tolerance of %.1f standard errors." % MAX_SIGMA)
        if numpy.any(numpy.abs(velocity_mean / velocity_stderr) > MAX_SIGMA):
            print "mean velocity (nm/ps)"
            print velocity_mean
            print "stderr (nm/ps)"
            print velocity_stderr
            print "nsigma"
            print velocity_mean / velocity_stderr
            raise Exception("Mean velocity exceeds error tolerance of %.1f standard errors." % MAX_SIGMA)
        
    if verbose: print "PASSED"
    return 
Пример #11
0
def test_replica_exchange(mpicomm=None, verbose=True):
    """
    Test that free energies and avergae potential energies of a 3D harmonic oscillator are correctly computed.

    TODO

    * Test ParallelTempering and HamiltonianExchange subclasses as well.
    * Test with different combinations of input parameters.
    
    """    

    if verbose and ((not mpicomm) or (mpicomm.rank==0)): print "Testing replica exchange facility with harmonic oscillators: ",

    # Create test system of harmonic oscillators
    import testsystems
    [system, coordinates] = testsystems.HarmonicOscillatorArray()

    # Define mass of carbon atom.
    mass = 12.0 * units.amu

    # Define thermodynamic states.
    from thermodynamics import ThermodynamicState
    states = list() # thermodynamic states
    sigmas = [0.2, 0.3, 0.4] * units.angstroms # standard deviations: beta K = 1/sigma^2 so K = 1/(beta sigma^2)
    temperatures = [300.0, 350.0, 400.0] * units.kelvin # temperatures
    seed_positions = list()
    analytical_results = list()
    f_i_analytical = list() # dimensionless free energies
    u_i_analytical = list() # reduced potential
    for (sigma, temperature) in zip(sigmas, temperatures):
        # Compute corresponding spring constant.
        kB = units.BOLTZMANN_CONSTANT_kB * units.AVOGADRO_CONSTANT_NA    
        kT = kB * temperature # thermal energy
        beta = 1.0 / kT # inverse temperature
        K = 1.0 / (beta * sigma**2)
        # Create harmonic oscillator system.
        [system, positions] = testsystems.HarmonicOscillator(K=K, mass=mass, mm=openmm)
        # Create thermodynamic state.
        state = ThermodynamicState(system=system, temperature=temperature)
        # Append thermodynamic state and positions.
        states.append(state)
        seed_positions.append(positions) 
        # Store analytical results.
        results = computeHarmonicOscillatorExpectations(K, mass, temperature) 
        analytical_results.append(results)
        f_i_analytical.append(results['f'])
        reduced_potential = results['potential']['mean'] / kT
        u_i_analytical.append(reduced_potential)
        
    # Compute analytical Delta_f_ij
    nstates = len(f_i_analytical)
    f_i_analytical = numpy.array(f_i_analytical)
    u_i_analytical = numpy.array(u_i_analytical)
    s_i_analytical = u_i_analytical - f_i_analytical
    Delta_f_ij_analytical = numpy.zeros([nstates,nstates], numpy.float64)
    Delta_u_ij_analytical = numpy.zeros([nstates,nstates], numpy.float64)
    Delta_s_ij_analytical = numpy.zeros([nstates,nstates], numpy.float64)
    for i in range(nstates):
        for j in range(nstates):
            Delta_f_ij_analytical[i,j] = f_i_analytical[j] - f_i_analytical[i]
            Delta_u_ij_analytical[i,j] = u_i_analytical[j] - u_i_analytical[i]
            Delta_s_ij_analytical[i,j] = s_i_analytical[j] - s_i_analytical[i]

    # Define file for temporary storage.
    import tempfile # use a temporary file
    file = tempfile.NamedTemporaryFile(delete=False)    
    store_filename = file.name
    #print "node %d : Storing data in temporary file: %s" % (mpicomm.rank, str(store_filename)) # DEBUG
    
    # Create and configure simulation object.
    from repex import ReplicaExchange
    simulation = ReplicaExchange(states, seed_positions, store_filename, mpicomm=mpicomm) # initialize the replica-exchange simulation
    simulation.number_of_iterations = 1000 # set the simulation to only run 2 iterations
    simulation.timestep = 2.0 * units.femtoseconds # set the timestep for integration
    simulation.nsteps_per_iteration = 500 # run 500 timesteps per iteration
    simulation.collision_rate = 0.001 / units.picosecond # DEBUG: Use a low collision rate
    simulation.platform = openmm.Platform.getPlatformByName('Reference') # use reference platform
    simulation.verbose = True # DEBUG

    # Run simulation.
    simulation.run() # run the simulation
    
    # Stop here if not root node.
    if mpicomm and (mpicomm.rank != 0): return

    # Analyze simulation to compute free energies.
    analysis = simulation.analyze()

    # TODO: Check if deviations exceed tolerance.
    Delta_f_ij = analysis['Delta_f_ij']
    dDelta_f_ij = analysis['dDelta_f_ij']
    error = Delta_f_ij - Delta_f_ij_analytical
    indices = numpy.where(dDelta_f_ij > 0.0)
    nsigma = numpy.zeros([nstates,nstates], numpy.float32)
    nsigma[indices] = error[indices] / dDelta_f_ij[indices]
    MAX_SIGMA = 6.0 # maximum allowed number of standard errors
    if numpy.any(nsigma > MAX_SIGMA):
        print "Delta_f_ij"
        print Delta_f_ij
        print "Delta_f_ij_analytical"
        print Delta_f_ij_analytical
        print "error"
        print error
        print "stderr"
        print dDelta_f_ij
        print "nsigma"
        print nsigma
        raise Exception("Dimensionless free energy difference exceeds MAX_SIGMA of %.1f" % MAX_SIGMA)

    error = analysis['Delta_u_ij'] - Delta_u_ij_analytical
    nsigma = numpy.zeros([nstates,nstates], numpy.float32)
    nsigma[indices] = error[indices] / dDelta_f_ij[indices]
    if numpy.any(nsigma > MAX_SIGMA):
        print "Delta_u_ij"
        print analysis['Delta_u_ij']
        print "Delta_u_ij_analytical"
        print Delta_u_ij_analytical
        print "error"
        print error
        print "nsigma"
        print nsigma
        raise Exception("Dimensionless potential energy difference exceeds MAX_SIGMA of %.1f" % MAX_SIGMA)

    if verbose: print "PASSED."
    return 
Пример #12
0
    def __init__(self, temperature, nbins, store_filename, protocol=None, mm=None):
        """
        Initialize a Hamiltonian exchange simulation object.

        ARGUMENTS

        store_filename (string) - name of NetCDF file to bind to for simulation output and checkpointing

        OPTIONAL ARGUMENTS

        protocol (dict) - Optional protocol to use for specifying simulation protocol as a dict. Provided keywords will be matched to object variables to replace defaults.

        NOTES

        von Mises distribution used for restraints

        http://en.wikipedia.org/wiki/Von_Mises_distribution

        """

        import simtk.pyopenmm.extras.testsystems as testsystems
        
        # Create reference system and state.        
        [system, coordinates] = testsystems.AlanineDipeptideImplicit()
        self.reference_system = system
        self.reference_state = repex.ThermodynamicState(system=system, temperature=temperature)

        self.nbins = nbins
        self.kT = (repex.kB * temperature)
        self.beta = 1.0 / self.kT

        self.delta = 360.0 / float(nbins) * units.degrees # bin spacing (angular)
        self.sigma = self.delta/3.0 # standard deviation (angular)
        self.kappa = (self.sigma / units.radians)**(-2) # kappa parameter (unitless)

        # Create list of thermodynamic states with different bias potentials.
        states = list()
        # Create a state without a biasing potential.
        [system, coordinates] = testsystems.AlanineDipeptideImplicit()
        state = repex.ThermodynamicState(system=system, temperature=temperature)
        states.append(state)        
        # Create states with biasing potentials.
        for phi_index in range(nbins):
            for psi_index in range(nbins):
                print "bin (%d,%d)" % (phi_index, psi_index)
                # Create system.
                [system, coordinates] = testsystems.AlanineDipeptideImplicit()                
                # Add biasing potentials.
                phi0 = (float(phi_index) + 0.5) * self.delta - 180.0 * units.degrees 
                psi0 = (float(psi_index) + 0.5) * self.delta - 180.0 * units.degrees 
                force = openmm.CustomTorsionForce('-kT * kappa * cos(theta - theta0)')
                force.addGlobalParameter('kT', self.kT / units.kilojoules_per_mole)
                force.addPerTorsionParameter('kappa')  
                force.addPerTorsionParameter('theta0')
                force.addTorsion(4, 6, 8, 14, [self.kappa, phi0 / units.radians])
                force.addTorsion(6, 8, 14, 16, [self.kappa, psi0 / units.radians])            
                system.addForce(force)
                # Add state.
                state = repex.ThermodynamicState(system=system, temperature=temperature)
                states.append(state)

        # Initialize replica-exchange simlulation.
        ReplicaExchange.__init__(self, states, coordinates, store_filename, protocol=protocol, mm=mm)

        # Override title.
        self.title = '2D umbrella sampling replica-exchange simulation created on %s' % time.asctime(time.localtime())
        
        return
Пример #13
0
import tempfile
file = tempfile.NamedTemporaryFile() # use a temporary file for testing -- you will want to keep this file, since it stores output and checkpoint data

# Select platform: one of 'Reference' (CPU-only), 'Cuda' (NVIDIA Cuda), or 'OpenCL' (for OS X 10.6 with OpenCL OpenMM compiled)
platform = simtk.openmm.Platform.getPlatformByName("OpenCL")    
platform = simtk.openmm.Platform.getPlatformByName("Cuda")    

# Set up device to bind to.
print "Selecting MPI communicator and selecting a GPU device..."
from mpi4py import MPI # MPI wrapper
hostname = os.uname()[1]
ngpus = 6 # number of GPUs per system
comm = MPI.COMM_WORLD # MPI communicator
deviceid = comm.rank % ngpus # select a unique GPU for this node assuming block allocation (not round-robin)
platform.setPropertyDefaultValue('CudaDeviceIndex', '%d' % deviceid) # select Cuda device index
platform.setPropertyDefaultValue('OpenCLDeviceIndex', '%d' % deviceid) # select OpenCL device index
print "node '%s' deviceid %d / %d, MPI rank %d / %d" % (hostname, deviceid, ngpus, comm.rank, comm.size)
# Make sure random number generators have unique seeds.
seed = numpy.random.randint(sys.maxint - comm.size) + comm.rank
numpy.random.seed(seed)

# Set up replica exchange simulation.
simulation = ReplicaExchange(states, coordinates, file.name, mpicomm=comm) # initialize the replica-exchange simulation
simulation.verbose = True
simulation.number_of_iterations = 100 # set the simulation to only run 2 iterations
simulation.timestep = 2.0 * units.femtoseconds # set the timestep for integration
simulation.nsteps_per_iteration = 500 # run 500 timesteps per iteration
simulation.platform = platform
simulation.run() # run the simulation