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
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
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))
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