def metropolis_sim_epoch(Lattice, K, nearest_neighbors=1): ''' :param Lattice: :param K: beta*J, temperature/coupling strength :param nearest_neighbors: number of nearest neighbors :return: ''' N = Lattice.shape N_sites = np.prod(N) for i in range(N_sites): #convert i to a coordinate r = np.unravel_index(i, N) site = Lattice[r] # propose a change proposal = -site # calculate energy change from neighbors in this: NN = getNN(r, N, nearest_neighbors) deltaE = 0 for nn_site in NN: neighbor = Lattice[nn_site] deltaE += K * (neighbor * (site - proposal)) if (deltaE < 0): # accept immediately Lattice[r] = -1 * Lattice[r] else: # calculate Boltzmann Weight Boltzmann = np.exp(-deltaE) # generate random number p = np.random.rand() if (p < Boltzmann): Lattice[r] = -1 * Lattice[r] return Lattice
def SW_BFS(lattice, bonded, clusters, start, beta, J, nearest_neighbors=1): ''' function currently cannot generalize to dimensions higher than 2... main idea is that we populate a lattice with clusters according to SW using a BFS from a root coord :param lattice: lattice :param bonded: 1 or 0, indicates whether a site has been assigned to a cluster or not :param clusters: dictionary containing all existing clusters, keys are an integer denoting natural index of root of cluster :param start: root node of graph (x,y) :param beta: temperature :param J: strength of lattice coupling :param nearest_neighbors: number or NN to probe :return: ''' p = 1 - np.exp(-2 * beta * J) #bond forming probability N = lattice.shape visited = np.zeros(N) #indexes whether we have visited nodes during #this particular BFS search queue = list() if (bonded[tuple(start)] != 0): #cannot construct a cluster from this site return bonded, clusters, visited queue.append(start) cluster_spin = lattice[tuple(start)] color = np.max(bonded) + 1 ## need to make sub2ind work in arbitrary dimensions index = np.ravel_multi_index(tuple(start), dims=tuple(N), order='C') clusters[index] = list() #whatever the input coordinates are while (len(queue) > 0): #print(queue) r = tuple(queue.pop(0)) ##print(x,y) if (visited[r] == 0): #if not visited visited[r] = 1 clusters[index].append(r) #to see clusters, always use different numbers bonded[r] = color NN = getNN(r, N, nearest_neighbors) for nn_coords in NN: rn = tuple(nn_coords) if(lattice[rn] == cluster_spin and bonded[rn] == 0\ and visited[rn] == 0): #require spins to be aligned random = np.random.rand() if (random < p): # accept bond proposal queue.append(rn) #add coordinate to search clusters[index].append(rn) #add point to the cluster bonded[rn] = color #indicate site is no longer available return bonded, clusters, visited
def metropolis_sim_vectorized(Lattice, K, epochs, num_views=1): N = Lattice.shape N_sites = np.prod(N) epoch = 100 nearest_neighbors = 1 # begin iterating over epochs for t in range(epoch): print('epoch: ' + str(t)) computations_tracker = 0 # scan through every element of the lattice #for every site, propose a change as a matrix proposal_matrix = -Lattice #calculate energy change using the original Lattice # need a shift operator... for i in range(N_sites): # convert i to a coordinate r = np.unravel_index(i, N) site = Lattice[r] # propose a change proposal = -site # calculate energy change from neighbors in this: NN = getNN(r, N, nearest_neighbors) deltaE = 0 for a in NN: neighbor = Lattice[a[0], a[1]] deltaE += K * (neighbor * (site - proposal)) if ( deltaE < 0 ): # accept immediately...we initiate a change with every flip so that NN may be affected ## in a vectorized version, we would actually have to do this on a checkerboard... Lattice[r] = -1 * Lattice[r] else: # calculate Boltzmann Weight Boltzmann = np.exp(-deltaE) # generate random number p = np.random.rand() if (p < Boltzmann): Lattice[r] = -1 * Lattice[r] if (t % int(epochs / num_views) == 0): plt.imshow(Lattice) plt.show()
def metropolis_simulation(Lattice, K, epochs, thermalization=100, num_views=1, view_lattice=False): N = Lattice.shape N_sites = np.prod(N) nearest_neighbors = 1 # begin iterating over epochs data = list() for t in range(epochs): computations_tracker = 0 # scan through every element of the lattice for i in range(N_sites): #convert i to a coordinate r = np.unravel_index(i, N) computations_tracker += 1 site = Lattice[r] # propose a change proposal = -site # calculate energy change from neighbors in this: NN = getNN(r, N, nearest_neighbors) deltaE = 0 for nn_site in NN: neighbor = Lattice[nn_site] deltaE += K * (neighbor * (site - proposal)) if (deltaE < 0): # accept immediately Lattice[r] = -1 * Lattice[r] else: # calculate Boltzmann Weight Boltzmann = np.exp(-deltaE) # generate random number p = np.random.rand() if (p < Boltzmann): Lattice[r] = -1 * Lattice[r] if (t % int(epochs / num_views) == 0): print('epoch: ' + str(t)) if (t % int(epochs / num_views) == 0 and view_lattice): plt.imshow(Lattice) plt.show() if (t > thermalization): data.append(magnetization(Lattice)) return Lattice, data
def run_Wolff_epoch(Lattice, N, p): ''' run one wolff epoch :param Lattice: :param N: :param p: 1-exp(-2K); :return: ''' change_tracker = np.ones(N) visited = np.zeros(N) root = [] # generate random coordinate by sampling from uniform random... for i in range(len(N)): root.append(np.random.randint(0, N[i], 1)[0]) root = tuple(root) visited[root] = 1 C = [root] # denotes cluster coordinates F_old = [root] # old frontier change_tracker[root] = -1 while (len(F_old) != 0): F_new = [] for site in F_old: site_spin = Lattice[tuple(site)] # get neighbors NN_list = getNN(site, N, num_NN=1) for NN_site in NN_list: ## if we do the full search, this is bad, because nn = tuple(NN_site) if (Lattice[nn] == site_spin and visited[nn] == 0): if (np.random.rand() < p): F_new.append(nn) visited[nn] = 1 C.append(nn) change_tracker[nn] = -1 F_old = F_new Lattice = Lattice * change_tracker return Lattice
def Wolff_simulation(Lattice, K, epochs, thermalization_epochs=100, num_views=10): ''' :param Lattice: :param K: :param epochs: :param thermalization_epochs: :param num_views: :return: ''' plt.ion() ## wolff test using Frontier idea N = Lattice.shape # generate random particle Lattice_History = list() p = 1 - np.exp(-2 * K) data = list() for t in range(epochs): change_tracker = np.ones(N) visited = np.zeros(N) root = [] # generate random coordinate by sampling from uniform random... for i in range(len(N)): root.append(np.random.randint(0, N[i], 1)[0]) root = tuple(root) visited[root] = 1 C = [root] # denotes cluster coordinates F_old = [root] # old frontier change_tracker[root] = -1 while (len(F_old) != 0): F_new = [] for site in F_old: site_spin = Lattice[tuple(site)] # get neighbors NN_list = getNN(site, N, num_NN=1) for NN_site in NN_list: ## if we do the full search, this is bad, because nn = tuple(NN_site) if (Lattice[nn] == site_spin and visited[nn] == 0): if (np.random.rand() < p): F_new.append(nn) visited[nn] = 1 C.append(nn) change_tracker[nn] = -1 F_old = F_new # update the cluster Lattice = Lattice * change_tracker if (t > thermalization_epochs): data.append(magnetization(Lattice)) # for site in C: # Lattice[site] = -1 * Lattice[site] # if (t % int(epochs/num_views) == 0): # print('epoch: ' + str(t)); # plt.imshow(Lattice); # plt.pause(0.05) # plt.imshow(Lattice); # plt.show() return Lattice, data