예제 #1
0
    input_file = alg.file_names('pcomb', s)['s']
    input_data = np.loadtxt(input_file)

    # Unpack
    subdom = np.array(input_data[:, 0], dtype=np.int)
    mu = input_data[:, 1]
    weights = input_data[:, 2]
    E_active = input_data[:, 3]

    # Number of bins, mu positions of bins
    if TRAP == True:
        N_bins = dom.subdom[s]['bins']
        mu_bins = dom.get_local_mu_bins(s)
    else:
        N_bins = np.sum(bins)
        mu_bins = dom.get_global_mu_bins()

    # Array for unfolded histogram
    hist_unfld = np.zeros(N_bins)
    print "Nbins = ", N_bins

    # Round-trip stuff
    mu_lo = mu_bins[N_bins / 4]
    mu_hi = mu_bins[3 * (N_bins / 4)]
    tracker = -1  # neutral (neither 0 or 1) initial value
    rt_rate_list = []

    # Decorrelation length
    decorr_list = []

    # Find all the rows of -1's which denote that the simulation has been restarted
예제 #2
0
def get_Pmat_eigenvector(Cmat):
    """ Returns the transition matrix eigenvector and associated
        multicanonical weights estimate """

    lendata = len(Cmat)
    undersampled = np.where(Cmat.diagonal()<1000)[0]
        
    # Make a fresh copy - Cmat shouldn't be changed here
    Cmat_copy = np.copy(Cmat)

    # Pretend there aren't zeros on diagonal if there are
    if len(undersampled) != 0:
        Cmat_copy += np.diag(np.ones(lendata))

    # Symmetrise zeros in second off-diagonal
    #for j in range(lendata-3):
    #    if Cmat_copy[j,j+2] == 0: Cmat_copy[j+2,j] = 0
    #    if Cmat_copy[j+2,j] == 0: Cmat_copy[j,j+2] = 0
             
    # Separately normalise transitions from each bin
    Pmat = Cmat_to_Pmat(Cmat_copy)
                
    # Check TTT identity
    v = np.zeros(lendata)
    for i in range(lendata-2):
        left = Pmat[i+1,i] * Pmat[i+2,i+1] * Pmat[i,i+2]
        right = Pmat[i+2,i] * Pmat[i+1,i+2] * Pmat[i,i+1]
        if left != 0 and right != 0:
            v[i+1] = 1 - left / right
        else:
            v[i+1] = float('NaN')
    v_abs = np.abs(v)
    j = np.nanargmax(v_abs)
    print "TTT identity: detailed balance violation: max is %f in col %d" %(v_abs[j],j)
        
    # Pull out an estimate for the probability
    if len(undersampled) != 0:
        print "Attempting to compute eigenvector of undersampled transition matrix"
        eigvec = seq_undersampled(Pmat)
    else:
        print "Attempting to compute eigenvector using ", eigvec_method
        if eigvec_method == 'arpack':
            eigvec = arpack(Pmat)
        elif eigvec_method == 'sequential':
            eigvec = sequential(Pmat)
        
    # Scale by bin width and renormalise
    if TRAP == False:
        mu = dom.get_global_mu_bins()
        for i in range(len(eigvec)):
            s = dom.get_subdomain(mu[i])
            w = dom.subdom[s]['bin_width']
            eigvec[i] = eigvec[i] / w
        eigvec = eigvec / np.sum(eigvec)

    # Compute weights
    TMweights = np.log(eigvec)
    TMweights -= np.min(TMweights)
    TMweights = kT * TMweights
    
    # Smooth out undersampled bits
    # I don't know what to put here right now

    return TMweights
예제 #3
0
plt.rc('text',usetex=True)
font = {'family' : 'serif',
        'size' : 14}
plt.rc('font', **font)
plt.rcParams['axes.linewidth'] = 2

# Colours to distinguish between subdomains
mkrs = ['bo-', 'go-']

# Set up iteration of subdomains, processors
p_list = np.arange(Np)
if TRAP == True:
    Ns_eff = Ns
else:
    Ns_eff = 1
    mu_bins = dom.get_global_mu_bins() * B / float(Natoms)

##########################
## Cuts and diffusivity ##
##########################
if plottype == 'diff':

    # ---------------- #
    #  Make the plots  #
    # ---------------- #
    fig, ax = plt.subplots()
    ax.set_title("Cuts histogram")
    ax.set_xlabel(r"$\mu \times \beta/N$")
    ax.set_ylabel("Counts through the cut")
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
    
예제 #4
0
def run(atoms_alpha,
        atoms_beta,
        disp,
        binned_data,
        dyn_data,
        p,
        s,
        F=1,
        relax=False):

    # ------------------------------------------------- #
    #  Set simulation parameters and useful quantities  #
    # ------------------------------------------------- #
    lendata = len(binned_data['w'])  # length of weights
    kTlogF = kT * np.log(F)

    # Convert frequency parameters from sweeps to steps
    if relax == True:
        Nsteps = sweeps_relax * Natoms
    else:
        Nsteps = alg.Nsteps
    save_step = sweeps_save * Natoms
    series_step = int(sweeps_series * Natoms)
    recalc_step = sweeps_recalc * Natoms
    refresh_step = sweeps_refresh * Natoms

    # Set boundaries for this simulation
    if TRAP == True:  # restrict to subdomain 's'; local bin indices
        global_mu_min = dom.subdom[s]['min']
        global_mu_max = dom.subdom[s]['max']
        get_index = dom.get_local_index
        mu_bins = dom.get_local_mu_bins(s)
    else:  # can access entire domain; global bin indices
        global_mu_min = boundaries[0]
        global_mu_max = boundaries[-1]
        get_index = dom.get_global_index
        mu_bins = dom.get_global_mu_bins()

    # Set weights function
    if use_interpolated_weights == True:
        get_weight = interpolated_weight

        # Need to add bins to the edges of mu and weights for extrapolation
        mu_bins = np.concatenate((mu_bins, [0, 0]))
        extrapolate(mu_bins)
        binned_data['w'] = np.concatenate((binned_data['w'], [0, 0]))
        extrapolate(binned_data['w'])

        # Need to do the same for cuts since it uses mu_bins
        if track_dynamics == True:
            dyn_data['cu'] = np.concatenate((dyn_data['cu'], [0, 0]))

    else:
        get_weight = discrete_weight

    # ------------------------ #
    #  Initialise usual stuff  #
    # ------------------------ #
    # Get initial lattice energies and difference between them
    old_E_alpha, old_E_beta = lattice_energies(atoms_alpha, atoms_beta)
    old_mu = old_E_alpha - old_E_beta
    new_mu = old_mu

    # For a global simulation, the initial subdomain (corresponding to the
    # input disp vector) needs to be computed
    if TRAP != True:
        s = dom.get_subdomain(old_mu)

    # Initial index and weight
    old_index = get_index(old_mu, s)
    old_weight = get_weight(old_mu, old_index, mu_bins, binned_data['w'])

    # Active lattice
    if s < dom.s_cross:  # start with lattice alpha(1) active
        ACT = 1
    elif s > dom.s_cross:  # start with lattice beta(-1) active
        ACT = -1
    else:  # randomise
        ACT = np.random.choice([-1, 1])

    # Flag for histogram flatness
    FLAT = 1  # start with 1 < f if wang-landau, otherwise f = 1 = FLAT

    # Initialise counters
    step = 1
    moves = 0
    retakes = 0
    switches = 0

    # ---------------------------- #
    #  Initialise 'dynamics' info  #
    # ---------------------------- #
    if track_dynamics == True:

        cuts = {'counter': 0, 'old_mu': old_mu, 'new_mu': old_mu}

        if TRAP == True:
            rt_min = 0
            rt_max = lendata - 1
        else:
            rt_min = np.argmax(binned_data['w'][mu_bins < 0])
            rt_max = np.argmax(binned_data['w'][mu_bins > 0]) + len(
                mu_bins[mu_bins < 0])

        rtrips = {
            'minmax': (0, rt_min, rt_max),
            'counts': 0,
            'flag': int(dyn_data['rt'][4])
        }

        # Mini transition matrix only works for TRAP == True (due to indexing)
        if TRAP == True:
            minimat = {
                'counter': 0,
                'root_index': old_index,
                'old_index': dyn.get_minibin_index(old_mu, s, old_index),
                'Pprod': 1
            }

    # --------------------------- #
    #  Open file for data series  #
    # --------------------------- #
    if track_series == True:
        series_file = alg.file_names('output', s, p)['s']
        series = open(series_file, 'a')

    # ------------------------------------------------------------ #
    #  Main loop over individual particle moves + switch attempts  #
    # ------------------------------------------------------------ #
    while FLAT < F or step <= Nsteps:  # Flat condition only relevant for Wang Landau

        # Refresh weights with eigenvector of transition matrix (TM only)
        if step % refresh_step == 0:
            alg.refresh_func(binned_data)

        # Write values from this step to the series file. Note high precision needed for mu
        if track_series == True:
            if step % series_step == 0:
                E_active = (0, old_E_alpha, old_E_beta)[ACT]
                series.write("%d %.10f %f %f \n" \
                        %(s, old_mu, old_weight, E_active) )

        # --------------------------------------------------- #
        #  Move a single particle and compute energy changes  #
        # --------------------------------------------------- #
        # Pick a random particle
        ipart = np.random.randint(0, Natoms)

        # Calculate old local energies for the two lattices before trial move
        old_local_energies = local_energy(atoms_alpha, atoms_beta, ipart)

        # Pick a random displacement and update lattice positions
        dr = (np.random.random(3) * 2.0 - 1.0) * dr_max
        dr_alpha = np.dot(dr, atoms_alpha.get_cell())
        dr_beta = np.dot(dr, atoms_beta.get_cell())
        atoms_alpha.positions[ipart, :] += dr_alpha
        atoms_beta.positions[ipart, :] += dr_beta

        # Calculate new local energies after trial move
        new_local_energies = local_energy(atoms_alpha, atoms_beta, ipart)

        # Calculate energy difference
        delta_local_energies = new_local_energies - old_local_energies

        # New energy difference between lattices
        if step % recalc_step == 1:  # full calculation
            new_E_alpha, new_E_beta = lattice_energies(atoms_alpha, atoms_beta)

            # Sanity check - don't want to be below ideal lattice energy!
            if new_E_alpha < E_ideal or new_E_beta < E_ideal:
                error(this_file,
                      "Oh no! Energy is less than that of an Ideal lattice.")

        else:  # update with local energy difference
            new_E_alpha = old_E_alpha + delta_local_energies[1]
            new_E_beta = old_E_beta + delta_local_energies[-1]

        new_mu = new_E_alpha - new_E_beta

        # ---------------- #
        #  Switch attempt  #
        # ---------------- #
        # Attempt a switch here 50% of the time - before any move evaluation
        coin = coinflip()
        ACT, switches = ((ACT, switches),
                         attempt_switch(new_mu, ACT, switches))[coin]

        # --------------------------------------- #
        #  Check if boundaries have been crossed  #
        # --------------------------------------- #
        # 'Global' boundaries are those that the simulation may not cross
        if new_mu < global_mu_min or new_mu > global_mu_max:

            # Update the bin from which the move was attempted
            old_weight, FLAT = alg.update_func(
                step,
                binned_data,
                delta_local_energies[ACT],
                old_index,
                old_index,
                old_index,  # only update edge bin
                old_mu,
                mu_bins,
                old_weight,
                get_weight,
                lendata,
                kTlogF,
                s)

            if track_dynamics == True:
                # Update data on simulation dynamics / mobility
                dyn.update_func(dyn_data, mu_bins, old_mu, old_index, s, cuts,
                                rtrips, False, abs(new_mu - old_mu),
                                abs(delta_local_energies[ACT]))

                if TRAP == True:
                    dyn.update_minimat(dyn_data, mu_bins, old_mu, old_index, s,
                                       minimat, True, 0)

            # Undo lattice positions update
            atoms_alpha.positions[ipart, :] -= dr_alpha
            atoms_beta.positions[ipart, :] -= dr_beta
            retakes += 1
            step += 1

            # Go back to the start of the while loop
            continue

        # Check if subdomain boundary crossed
        old_s = s
        if new_mu < dom.subdom[s]['min']:
            s -= 1
        elif new_mu > dom.subdom[s]['max']:
            s += 1

        # ---------------------- #
        #  Evaluate move result  #
        # ---------------------- #
        # Get index for arrays using mu
        new_index = get_index(new_mu, s)

        # Difference in weights augments delta_local_energy
        new_weight = get_weight(new_mu, new_index, mu_bins, binned_data['w'])
        augment = new_weight - old_weight

        # Accept/reject trial move with weighted energy difference
        expnt = -B * (delta_local_energies[ACT] + augment)
        accepted = accept_move(expnt)
        """ #Difference between bin-averaged weight and interpolated
        intra_bin_weight = old_weight - weights[old_index]
        #sampling_adjust = np.exp( B*intra_bin_weight ) # doesn't work: centre of bins?"""

        old_index_copy = old_index  # to update Cmat and extra info after move evaluation
        dmu = abs(new_mu - old_mu)  # to update dynamics

        # Update things according to whether move accepted
        if accepted == True:
            disp[ipart, :] += dr
            old_E_alpha = new_E_alpha
            old_E_beta = new_E_beta
            old_index = new_index
            old_weight = new_weight
            old_mu = new_mu
            moves += 1

            cuts_new_mu = new_mu

        else:
            atoms_alpha.positions[ipart, :] -= dr_alpha
            atoms_beta.positions[ipart, :] -= dr_beta
            s = old_s  # Account for possible subdomain change

            cuts_new_mu = old_mu

        # ------------------------ #
        #  Update bin information  #
        # ------------------------ #
        old_weight, FLAT = alg.update_func(step, binned_data,
                                           delta_local_energies[ACT],
                                           new_index, old_index,
                                           old_index_copy, old_mu, mu_bins,
                                           old_weight, get_weight, lendata,
                                           kTlogF, s)

        # ------------------------------------ #
        #  Update data on simulation dynamics  #
        # ------------------------------------ #
        if track_dynamics == True:

            # Update data on simulation dynamics / mobility
            cuts['new_mu'] = cuts_new_mu
            dyn.update_func(dyn_data, mu_bins, old_mu, old_index, s, cuts,
                            rtrips, accepted, dmu,
                            abs(delta_local_energies[ACT]))

            if TRAP == True:
                dyn.update_minimat(dyn_data, mu_bins, old_mu, old_index, s,
                                   minimat, accepted, expnt)

        # ---------------- #
        #  Switch attempt  #
        # ---------------- #
        # 50/50 chance of attempting a switch after the move
        ACT, switches = (attempt_switch(old_mu, ACT,
                                        switches), (ACT, switches))[coin]

        # ------------------- #
        #  Save periodically  #
        # ------------------- #
        if step % save_step == 0:
            alg.save_func(binned_data, mu_bins, step, s, p)

            # Take this opportunity to reset centre of mass
            atoms_alpha.positions = atoms_alpha.positions - atoms_alpha.get_center_of_mass(
            )
            atoms_beta.positions = atoms_beta.positions - atoms_beta.get_center_of_mass(
            )

        step += 1

    # End main loop

    print "- Steps: ", step
    print "- Moves: ", moves
    print "- Retakes: ", retakes
    print "- Switches: ", switches

    # --------------------------------------------- #
    #  Finalise things before returning to main.py  #
    # --------------------------------------------- #
    # Close series file
    if track_series == True:
        series.close()

    if track_dynamics == True:
        # Round trip output file
        dyn_data['rt'][0] += step
        dyn_data['rt'][1] += switches
        dyn_data['rt'][2] += rtrips['counts']  # half round trips
        rt_rate = float(0.5 * dyn_data['rt'][2] *
                        Natoms) / dyn_data['rt'][0]  # rtrips per sweep
        dyn_data['rt'][3] = 1.0 / rt_rate  # sweeps per rtrip
        dyn_data['rt'][4] = rtrips['flag']  # to be picked up by next iteration

    # Compute eigenvector and refresh weights
    alg.refresh_func(binned_data)

    # If interpolated weights used, remove those extrapolated bins / 'ghost points'
    if len(binned_data['w']) != len(binned_data['h']):
        binned_data['w'] = binned_data['w'][:-2]
        if track_dynamics == True:
            dyn_data['cu'] = dyn_data['cu'][:-2]

    # Only care about difference in weights, set minimum to zero
    binned_data['w'] -= np.min(binned_data['w'])

    return step