Example #1
0
def check_domain():
    """ Check sensible subdomain strategy """
        
    if len(boundaries) != Ns + 1 or len(bins) != Ns or len(rules) != Ns:
        error(this_file, "Mismatch between number of subdomains and number of boundaries/bins/rules. \nMake sure there are Ns + 1 boundaries, Ns bins and Ns rules in params.py!")

    for i in range(len(boundaries)-1):
        if boundaries[i+1] <= boundaries[i]:
            error(this_file, "Mu boundaries do not increase monotonically from left to right.")

    # These are center-of-bin values
    mu_s_cross = dom.get_local_mu_bins(dom.s_cross)
    
    # Want a bin centered on mu=0
    mu_hi = mu_s_cross[dom.i_cross]
    mu_lo = mu_s_cross[dom.i_cross - 1]
    
    # If we've failed to get a bin centered on mu=0
    if np.allclose(mu_hi,0.0) == False: # rtol=1e-5, atol=1e-8
        
        print "Error:", this_file
        print "mu = 0 falls into a bin centered on mu = %1.8f, rather than 0." %mu_hi

        bound_hi = boundaries[dom.s_cross + 1]
        bound_lo = boundaries[dom.s_cross]

        rnd_bin_width = np.around(dom.subdom[dom.s_cross]['bin_width'],decimals=10)
        hbw = 0.5*rnd_bin_width
        bins_lo = dom.i_cross - dom.subdom[dom.s_cross]['l_bin_olap']
        bins_hi = bins[dom.s_cross] - bins_lo
        prop_bound_hi = bins_hi * rnd_bin_width
        prop_bound_lo = bins_lo * rnd_bin_width * -1
        
        print "Try %.10f --> %.10f,    %.10f --> %.10f" \
                %(bound_lo,prop_bound_lo+hbw,bound_hi,prop_bound_hi+hbw)
        print "Or %.10f --> %.10f,    %.10f --> %.10f" \
                %(bound_lo,prop_bound_lo-hbw,bound_hi,prop_bound_hi-hbw)
        
        print "Or change the number of bins and try again."
        exit(1)

    print "Subdomain strategy OK."
    return
Example #2
0
##############################
## Set up fine-grained grid ##
##############################
""" Sets up 'windows' centered on each regular bin, containing 'mini-bins'.
    This allows more precise measurement of local transition probabilities,
    while keeping relatively thick bins for everything else. """

# ------------------------- #
#  Iterate over subdomains  #
# ------------------------- #
subdom = []
for s in range(Ns):

    # These are the centres of the windows
    mu_bins = dom.get_local_mu_bins(s)

    # Widths in terms of mu
    minibin_width = dom.subdom[s]['bin_width'] / float(minibins_per_bin)
    window_width = minibin_width * minibins_per_window

    # Dictionary of info for this subdomain, including a list of dictionaries
    # containing info about individual windows
    windows = {
        'mbin_width': minibin_width,
        'win_width': window_width,
        'win_info': []
    }

    # ---------------------------------- #
    #  Iterate over regular bin indices  #
Example #3
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
Example #4
0
            input_files = alg.file_names('output', s, p)
            extra_input_files = dyn.file_names('output', s, p)

            # Load input files
            this_hist = np.loadtxt(input_files['h'])
            this_cuts = np.loadtxt(extra_input_files['cu'])
            
            # Add to combined
            hist = hist + this_hist
            cuts = cuts + this_cuts
            
        if TRAP == True:
            # Scale by bin width
            cuts = cuts * dom.subdom[s]['bin_width']
            # Load mu subdomain
            mu_bins = dom.get_local_mu_bins(s) * B / float(Natoms)
        else:
            # Scale global data by bin widths for each subdomain
            bin_low = 0
            bin_high = 0
            for ss in range(Ns):
                bin_high += bins[ss]
                cuts[bin_low:bin_high] = cuts[bin_low:bin_high] * dom.subdom[ss]['bin_width']
                bin_low = bin_high

        # Formula given in Tian et a. (2014), though coefficient is arbitrary in this case
        cuts = 0.5*cuts
        diffusivity = np.pi / dyn.cuts_step * (cuts**2) / (hist**2)

        # The edge bins are not well estimated with the cuts method implemented
        diffusivity[0] = diffusivity[1] + 0.25*(diffusivity[1] - diffusivity[4])
Example #5
0
    error(this_file, "No file name found in list of argument variables.")

# Load data
input_data = np.loadtxt(input_file[1]) # index 0 is the plot script itself

# Extract subdomain index if provided as argument variable 
# This will be the first int given in the argv list
s = [v for v in argv if v.isdigit()]

# If no subdomain given as argument variable, plot global data
if len(s) == 0:
    mu_bins = dom.get_global_mu_bins() * B / float(Natoms)
    s = 'all'
else:
    s = s[0]
    mu_bins = dom.get_local_mu_bins(int(s)) * B / float(Natoms)

# Check data and mu are the same size
if len(input_data) != len(mu_bins):
    error(this_file, "Length of input data does not match number of mu bins in subdomain: "+s)


# Plot parameters
plt.rc('text',usetex=True)
font = {'family' : 'serif',
        'size' : 14}
plt.rc('font', **font)
plt.rcParams['axes.linewidth'] = 2

# Create plot
fig, ax = plt.subplots()