def check_shuffle_file(): """ Check for a file for shuffled indices. Create a new one if not. """ # Check if shuffle file exists input_file = "shuffled_indices.out" if os.path.exists(input_file) != True: # Any existing disp files should be deleted if the shuffle file has been lost disp_file = alg.file_names('input', 0, 0)['d'] if os.path.exists(disp_file) == True: error(this_file, "Unfortunately, since the shuffle file has been lost, the initial displacement vectors must be reset to zero. Please move or delete files %s etc." %disp_file) # Create a new array and file for shuffled indices shuffled_indices = np.arange(Natoms) np.random.shuffle(shuffled_indices) print "Saving new shuffled indices to ", input_file np.savetxt(input_file, shuffled_indices.astype(int), fmt='%i')
if TRAP == True: Ns_eff = Ns # multiple procs on same subdomain already combined in join_procs else: Ns_eff = 1 # there may be more than 1 subdom, but each process is global - simulation has access to entire domain # ----------------------------------- # # Iterate over different subdomains # # ----------------------------------- # for s in range(Ns_eff): print "" if TRAP == True: print "Series data from subdomain: ", s else: print "Series data from global domain." # Load the series data 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()
def gen_input_files(): """ If starting a new fixed-weights simulation, empty files will need to be created to be imported during the first loop iteration. """ if algorithm not in ('multicanonical', 'transition'): return print "" for p in range(Np): # Map to subdomain index s = ini.map_proc_to_subdom(p) # Input files as decided by program input_files = alg.file_names('input', s, p) sname, pname = ini.naming_system(s, p) # User input files from params params_input_files = {'d': None, 'w': params_weights_file, 'h': params_hist_file, 'c': params_Cmat_file, 's': params_series_file,} # Check if we need to add '_pY_sX' params_weights_file_alt = ini.rename_inputs(params_weights_file, sname[0], '') params_hist_file_alt = ini.rename_inputs(params_hist_file, sname[0], pname[0]) params_Cmat_file_alt = ini.rename_inputs(params_Cmat_file, sname[0], pname[0]) params_series_file_alt = ini.rename_inputs(params_series_file, sname[0], pname[0]) params_input_files_alt = {'d': None, 'w': params_weights_file_alt, 'h': params_hist_file_alt, 'c': params_Cmat_file_alt, 's': params_series_file_alt} # Correct sizes size = ini.get_size(s) start_files = {'d': np.zeros((Natoms, 3)), 'w': np.zeros(size), 'h': np.zeros(size), 'c': np.zeros((size,size)), 's': [np.ones(5)*-1,]} for key in params_input_files.keys(): # If an input file has been given in params.py if params_input_files[key] != None: # If the default input file doesn't yet exist, # We need to save a copy of the params file to this name if os.path.exists(input_files[key]) == False: # First check for the params file modified by '_pY_sX' if os.path.exists(params_input_files_alt[key]) == True: tmp = np.loadtxt(params_input_files_alt[key]) print " Copying %s -> %s" %(params_input_files_alt[key], input_files[key]) np.savetxt(input_files[key], tmp) # Then check for the exact file name given in params.py elif os.path.exists(params_input_files[key]) == True: tmp = np.loadtxt(params_input_files[key]) print " Copying %s -> %s" %(params_input_files[key], input_files[key]) np.savetxt(input_files[key], tmp) # Error if params file hasn't been found else: error(this_file, " Neither files %s or %s not found." %(params_input_files_alt[key],params_input_files[key])) # If the default input file does exist, leave it alone else: print " File %s exists and will be read as input" %input_files[key] print "" print "File check completed. " return
# ------------------------------------------- # # Compile a list of input/output file names # # ------------------------------------------- # # Check for sensible argv[1] if argv[1] not in ('w', 'c', 'h'): error(this_file, "argv[1] should be 'w', 'c', or 'h'") # Input file names for each subdomain input_file_list = [] for s in range(Ns): if len(argv) > 2: # file stem passed as argument input_file = argv[2] + "_s" + str(s) + ".out" else: # default file names input_file = alg.file_names(stage_in, s)[argv[1]] input_file_list.append(input_file) # Output file name if len(argv) > 2: # use argument file stem as output file stem output_file = argv[2] + "_scomb.out" else: output_file = alg.file_names('scomb')[argv[1]] # --------------------------------------------- # # Optional: plot all subdomains in one figure # # --------------------------------------------- # def plot_combined(data_list, mu_list): ''' Plot combined subdomain data, either joined up or not '''
if save == True: global_diffusivity = [] # ------------------------- # # Iterate over subdomains # # ------------------------- # for s in range(Ns_eff): # Initialise arrays for combined data within subdom size = ini.get_size(s) hist = np.zeros(size) cuts = np.zeros(size) for p in p_list[s::Ns_eff]: # Get file names to load 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)
size = ini.get_size(s) steps = ls.run(atoms_alpha, atoms_beta, disp, { 'w': np.zeros(size), 'h': np.zeros(size), 'c': np.zeros((size, size)) }, dyn_data, p, s, relax=True) # Separate independent runs by saving this line to the series output file if track_series == True: series_file = alg.file_names('output', s, p)['s'] series = open(series_file, 'a') series.write("-1 -1 -1 -1 \n") series.close() ################################################################################### ## ## ## Run a Lattice-switch Monte Carlo simulation ## ## by calling lattice_switch.run() ## ## ## ################################################################################### ################### ## Wang-Landau ## ################### if algorithm == 'wang_landau':
ax.set_ylabel(r"$E \times \beta/N$") # Colours distinguish between subdomains colours = ('tab:gray', 'k') # Initialise arrays for averaging energy E_mean = np.zeros(np.sum(bins)) counts = np.zeros(np.sum(bins)) # ----------------------------------- # # Iterate over different subdomains # # ----------------------------------- # for s in range(Ns_eff): # Load the series data 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] # Decide how frequently we want to add a point to the scatter plot Nrows = len(subdom) addpoint = int(Nrows / points_per_sub) # Initialise lists for scatter data E_scatter = [] mu_scatter = []
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
data_comb = [] # ------------------------------------------------------------ # # Sum over processors operating in the same subdomain/domain # # ------------------------------------------------------------ # for p in p_list[s::Ns_eff]: if TRAP == True: # Check correct mapping of processor to subdomain s_check = ini.map_proc_to_subdom(p) if s_check != s: error(this_file, "Mapping p -> s has gone wrong \nExpected p%d -> s%d, but got s%d" %(p,s_check,s)) # Load files (output by main.py) input_file = alg.file_names('output', s, p)[argv[1]] this_data = np.loadtxt(input_file) # Add to sum if argv[1] in ('h', 'c'): data_comb = data_comb + this_data elif argv[1] == 's': ldc = len(data_comb) tmp = np.zeros( (ldc+len(this_data), 4) ) if ldc > 0: tmp[:ldc,:] = data_comb tmp[ldc:,:] = this_data data_comb = tmp
import numpy as np import matplotlib.pyplot as plt from sys import argv, exit from os.path import basename from params import * if algorithm == 'wang_landau': import wang_landau as alg elif algorithm == 'multicanonical': import multicanonical as alg elif algorithm == 'transition': import transition_matrix as alg # Name of this file this_file = basename(__file__) deltaF_file = alg.file_names('dF') # Can specify a non-default window size via argument variable if len(argv) > 2: window = int(argv[2]) # Can specify non-default data file if len(argv) > 3: deltaF_file = argv[3] ###################################################### ## Functions to compute mean and standard deviation ## ###################################################### ''' ########### Not convinced that this is working! ########## def weighted_estimators(deltaF_series, error_series):