Base MPI Parallel Tempering

class mcpele.parallel_tempering._MPI_Parallel_Tempering(mcrunner, Tmax, Tmin, max_ptiter, pfreq=1, skip=0, print_status=True, base_directory=None, verbose=False)[source][source]

Abstract class for MPI Parallel Tempering calculations

_MPI_Parallel_Tempering implements all the basic MPI routines. The initialisation function and the method to find the swap pattern need to implemented in a specific child method.

The replica exchange method (REM) or parallel tempering (PT) is a Monte Carlo scheme that targets the slow equilibration of systems characterised by large barriers in their free energy landscape. In REM \(n\) replicas of the system are simulated simultaneously in the canonical (NVT) ensemble. These systems differ in temperature and, while the high temperature replicas explore the high energy regions of phase space, easily crossing large free energy barriers, the low temperature replicas explore the low lying regions of the energy landscape. In the hierarchical picture of the energy landscape, in which intra-funnel equilibration is fast and inter-funnel is slow, the high temperature replicas explore the energy landscape hopping between funnels, while the low temperature replicas explore individual funnels accurately. The idea of REM is to introduce moves that swap configurations between the different replicas, thus making the high energy regions available to the low temperature simulations and vice versa. It is not hard to see why this makes the exploration of configurational space more efficient, thus accelerating equilibration.

The acceptance rule for parallel tempering is

\[P( x_i \Rightarrow x_j) = min \{ 1, \exp [- (\beta_j - \beta_i) (E_i - E_j)] \}\]

The choice of temperature scale is very important for efficient equilibration to occur. From the acceptance rule we see that the acceptance will be suppressed exponentially by large differences in energy between the two configurations, just as for the Metropolis algorithm, but also by large differences in temperature. Thus, we must keep this product of differences as small as possible, to allow for efficient swapping. As a rule of thumb this can be achieved by using a scale of geometrically increasing temperatures.

It is important to note that REM is a truly equilibrium Monte Carlo method: the microscopic equilibrium of each ensemble is not disturbed by the swaps, hence the ensemble averages for each replica are just as valid as for ordinary Monte Carlo simulations (unlike simulated annealing, for which ensemble averages are not well defined). In addition, ensemble averages for the extended ensemble can be obtained by histogram reweighting technique. We also highlight the fact that REM moves are very cheap to perform since they do not require additional energy evaluations.

Note

An optimal Parallel Tempering strategy should make sure that all MCMC walks take roughly the same amount of time. Besides this fundamental consideration, note that root (rank=0) is not an evil master but rather an enlightened dictator that leads by example: root is responsible to assign jobs and control parameters (e.g. temperature) to the slaves but it also performs MCMC walks along with them. For this reason it might be optimal to give root a set of control parameters for which the simulation is leaner so that it can start doing its own things while the slaves finish their work.

Parameters:

mcrunner : _BaseMCrunner

object of _BaseMCrunner that performs the MCMC walks

Tmax : double

maximum temperature to simulate (or equivalent control parameters)

Tmin : double

minimum temperature to simulate (or equivalent control parameters)

max_ptiter : int

maximum number of Parallel Tempering iterations

pfreq : int

frequency with which histogram and other information is dumped to a file

skip : int

number of parallel tempering iteration for which swaps should not be performed. Swaps should be avoided for instance while adjusting the step size

print_status : bool

choose whether to print MCrunner status at each iteration

base_directory : string

path to base directory where to save output

verbose : bool

print verbose output to terminal

Attributes

mcrunner (_BaseMCrunner) object of _BaseMCrunner that performs the MCMC walks
nproc (int) number of parallel cores
rank (int) MPI rank (identifier of the particular core), master has rank=0
Tmax (double) maximum temperature to simulate (or equivalent control parameters)
Tmin (double) minimum temperature to simulate (or equivalent control parameters)
max_ptiter (int) maximum number of Parallel Tempering iterations
ptiter (int) count of current parallel tempering iteration
pfreq (int) frequency with which histogram and other information is dumped to a file
no_exchange_int (neg int) this NEGATIVE number in exchange_pattern() means that no exchange should be attempted
skip (int) number of parallel tempering iteration for which swaps should not be performed. Swaps should be avoided for instance while adjusting the step size
swap_accepted_count (int) count of accepted swaps
swap_rejected_count (int) count of rejected swaps
nodelist (list) list of ranks (should be integers from 0 to nprocs)
base_directory (string) path to base directory where to save output
ex_outstream (stream) stream to output exchanges informations
initialised (bool) records whether PT has been initialised
print_status (bool) choose whether to print MCrunner status at each iteration
verbose (bool) print verbose output to terminal
_attempt_exchange()[source][source]

This function brings together all the functions necessary to attempt a configuration swap

This function is structures as follows:

  • root gathers the energies from the slaves
  • root decides who will swap with whom
  • root to each processor the rank of its chosen partner (buddy)
  • processors exchange configuration and energy
_broadcast_data(in_data, adim, dtype='d')[source][source]

Identical arrays are broadcasted from root to all other processes

Parameters:

in_data : numpy.array

incoming array (from the master) to be broadcasted

adim : int

size of the in_data array

dtype : dtype

type of the elements of the array

Returns:

bcast_data : numpy.array

array of length adim

_close_flush()[source][source]

Abstract method responsible for printing and/or dumping the all streams at the end of the calculation

_exchange_pairs(exchange_buddy, data)[source][source]

Return data from the pair exchange, otherwise return the data unaltered.

Warning

the replica sends to exchange_partner and receives from it, replacing source with self.rank would cause a deadlock

Parameters:

exchange_buddy : int

rank of processor with which to swap

data : numpy.array

array of data to exchage

Returns:

data : numpy.array

the send data buffer is replaced with the receive data

_find_exchange_buddy(Earray)[source][source]

Abstract method to determines the exchange pattern, it needs to be overwritten.

An exchange pattern array is constructed, filled with self.no_exchange_int which signifies that no exchange should be attempted. This value is replaced with the rank of the processor with which to perform the swap if the swap attempt is successful. The exchange partner is then scattered to the other processors.

Parameters:

Earray : numpy.array

array of energies (one from each core)

_gather_data(in_send_array, dtype='d')[source][source]

Method to gather data in equal ordered chunks from replicas (it relies on the rank of the replica)

Note

gather assumes that all the subprocess are sending the same amount of data to root, to send variable amounts of data must use the MPI_gatherv directive

Parameters:

in_send_array : numpy.array

incoming array (from each process) to be sent to master

dtype : dtype

type of the elements of the array

Returns:

recv_array : numpy.array

array of length len(in_send_array)) * nproc

_gather_energies(E)[source][source]

gather energy of configurations from all processors

Parameters:

E : double

energy of each processor respectively

Returns:

recv_Earray : numpy.array

array of length nproc

_initialise()[source][source]

Perform all the tasks required prior to starting the computation including initialising the output files

_point_to_point_exchange_replace(dest, source, data)[source][source]

swap data between two processors

Note

the message sent buffer is replaced with the received message

Parameters:

dest : int

rank of processor with which to swap

source : int

rank of processor with which to swap

data : numpy.array

array of data to exchage

Returns:

data : numpy.array

the send data buffer is replaced with the receive data

_print_data()[source][source]

Abstract method responsible for printing and/or dumping the data, let it be printing the histograms or else

_print_status()[source][source]

Abstract method responsible for printing and/or dumping the status, let it be printing the histograms or else

_scatter_data(in_send_array, adim, dtype='d')[source][source]

Method to scatter data in equal ordered chunks among replica (it relies on the rank of the replica)

In simple terms it requires that adim % nproc = 0. If root scatters an array of size nproc then each core will receive the rank-th element of the array.

Parameters:

in_send_array : numpy.array

incoming array (from the master) to be scattered

adim : int

size of the in_send_array

dtype : dtype

type of the elements of the array

Returns:

recv_array : numpy.array

array of length adim/nproc

_scatter_single_value(send_array, dtype='d')[source][source]

Returns a single value from a scattered array for each replica (e.g. Temperature or swap partner)

Note

send array must be of the same length as the number of processors

Parameters:

send_array : numpy.array

incoming array (from the master) to be scattered

dtype : dtype

type of the elements of the array

Returns:

dtype

temperature or swap partner or else

one_iteration()[source][source]

Perform one parallel tempering iteration

Each PT iteration consists of the following steps:

  • set the coordinates
  • run the MCrunner for a predefined number of steps
  • collect the results (energy and new coordinates)
  • attempt an exchange
run()[source][source]

Run multiple single iterations, plus initialisation if MPI_PT has not been initialised yet