伊辛模型大都会算法
Ising model metropolis algorithm
我正在尝试使用大都会算法来模拟伊辛模型。我遇到的问题是代码不会一直稳定下来。对于高 beta 值,能量偏好应该是自旋都在同一方向,但是在我的代码中,即使它大部分时间都有效,偶尔会有水平或垂直的自旋向上然后向下旋转的带网格(grid2)。然后,这会使平均旋转计数稳定在一个不是 1 或 -1 的值,这对于高 Beta 应该是这样。我知道问题出在哪里 - 当这种情况发生时,我在边界处的增量能量是 4,因此在高 beta 下,这使得自旋不太可能翻转,因此它最终被卡住了。我在想也许我 运行 的时间不够长,但在变量浏览器上查看 average_spin_count 它似乎在最多 200 圈后稳定下来。我也在考虑也许使用对角线,但其他代码和模拟似乎没有使用这个想法,所以我希望有人能指出我哪里出错了。 (您必须多次 运行 代码,直到遇到并非所有自旋 up/down 的情况)。谢谢
import numpy as np
import numpy.random as rnd
N = 20
#grid size
random_number = np.random.randint(0,1000)
prob = 0.5
#probability of starting with spin down.
np.random.seed(random_number)
grid =np.random.choice(list(range(-1, 0)) + list(range(1, 2)), size=(N, N), p=[prob,1-prob])
def find_energy(grid, r, c):
if r < N-1 and c < N-1:
energy = -((grid[r,c]*grid[r+1,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,c+1])+(grid[r,c]*grid[r,c-1]))
if r == (N-1) and c < N-1:
energy = -((grid[r,c]*grid[0,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,c+1])+(grid[r,c]*grid[r,c-1]))
if c == (N-1) and r < N-1:
energy = -((grid[r,c]*grid[r+1,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,0])+(grid[r,c]*grid[r,c-1]))
if c== (N-1) and r==(N-1):
energy = -((grid[r,c]*grid[0,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,0])+(grid[r,c]*grid[r,c-1]))
return energy
def get_coordinate():
"""Returns a random coordinate as a tuple"""
return tuple(np.random.randint(0, high=N, size=(1, 2))[0])
def probability( delta_energy, beta):
probability = np.exp(-1*beta*delta_energy)
return probability
def compare_energies(n, beta):
total_number_spin_up=np.array([])
total_number_spin_down=np.array([])
for i in range(n):
original_point = get_coordinate()
original_energy = find_energy(grid, original_point[0], original_point[1])
new_energy = original_energy * -1
delta_energy = new_energy-original_energy
x = (original_point[0])
y = (original_point[1])
if delta_energy <= 0:
grid[x,y] = grid[x, y]*-1
#flips the spin
elif delta_energy > 0:
if probability(delta_energy, beta) > rnd.uniform(0,1):
grid[x,y] = (grid[x, y])*-1
number_of_spin_up = np.count_nonzero(grid == 1)
total_number_spin_up = np.append(total_number_spin_up,number_of_spin_up)
total_number_spin_down = np.append(total_number_spin_down, pow(N,2)-number_of_spin_up)
spin_up = total_number_spin_up[-1]
spin_down = total_number_spin_down[-1]
average_spin = (spin_up-spin_down)/N**2
return grid, average_spin
beta = 10
#runs the code to settle it.
average_spin_count = np.array([])
for i in range(300):
grid_2, average_spin = compare_energies(N**2, beta)
average_spin_count = np.append(average_spin_count, average_spin)
y = average_spin_count[-1]
如果你绘制这种情况的最终网格,你会看到会发生什么,以matplotlib
为例,见下文:
import matplotlib.pyplot as plt
plt.imshow(grid)
plt.show()
你会发现 space 被分成了两个区域。或者,您可以如下初始化网格而不是随机数。
grid = np.zeros((N, N))
grid[:N//2] = 1
您将看到类似的行为。解决方法很简单。如果您计算边界处自旋翻转的能量和相应的概率,您会发现能量值为 -3,导致概率 9.76e-27
,对于给定的 beta 基本上是 0
。因此,这种状态非常稳定,300 次迭代内你可能看不到任何变化。
我正在尝试使用大都会算法来模拟伊辛模型。我遇到的问题是代码不会一直稳定下来。对于高 beta 值,能量偏好应该是自旋都在同一方向,但是在我的代码中,即使它大部分时间都有效,偶尔会有水平或垂直的自旋向上然后向下旋转的带网格(grid2)。然后,这会使平均旋转计数稳定在一个不是 1 或 -1 的值,这对于高 Beta 应该是这样。我知道问题出在哪里 - 当这种情况发生时,我在边界处的增量能量是 4,因此在高 beta 下,这使得自旋不太可能翻转,因此它最终被卡住了。我在想也许我 运行 的时间不够长,但在变量浏览器上查看 average_spin_count 它似乎在最多 200 圈后稳定下来。我也在考虑也许使用对角线,但其他代码和模拟似乎没有使用这个想法,所以我希望有人能指出我哪里出错了。 (您必须多次 运行 代码,直到遇到并非所有自旋 up/down 的情况)。谢谢
import numpy as np
import numpy.random as rnd
N = 20
#grid size
random_number = np.random.randint(0,1000)
prob = 0.5
#probability of starting with spin down.
np.random.seed(random_number)
grid =np.random.choice(list(range(-1, 0)) + list(range(1, 2)), size=(N, N), p=[prob,1-prob])
def find_energy(grid, r, c):
if r < N-1 and c < N-1:
energy = -((grid[r,c]*grid[r+1,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,c+1])+(grid[r,c]*grid[r,c-1]))
if r == (N-1) and c < N-1:
energy = -((grid[r,c]*grid[0,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,c+1])+(grid[r,c]*grid[r,c-1]))
if c == (N-1) and r < N-1:
energy = -((grid[r,c]*grid[r+1,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,0])+(grid[r,c]*grid[r,c-1]))
if c== (N-1) and r==(N-1):
energy = -((grid[r,c]*grid[0,c])+(grid[r,c]*grid[r-1,c])+
(grid[r,c]*grid[r,0])+(grid[r,c]*grid[r,c-1]))
return energy
def get_coordinate():
"""Returns a random coordinate as a tuple"""
return tuple(np.random.randint(0, high=N, size=(1, 2))[0])
def probability( delta_energy, beta):
probability = np.exp(-1*beta*delta_energy)
return probability
def compare_energies(n, beta):
total_number_spin_up=np.array([])
total_number_spin_down=np.array([])
for i in range(n):
original_point = get_coordinate()
original_energy = find_energy(grid, original_point[0], original_point[1])
new_energy = original_energy * -1
delta_energy = new_energy-original_energy
x = (original_point[0])
y = (original_point[1])
if delta_energy <= 0:
grid[x,y] = grid[x, y]*-1
#flips the spin
elif delta_energy > 0:
if probability(delta_energy, beta) > rnd.uniform(0,1):
grid[x,y] = (grid[x, y])*-1
number_of_spin_up = np.count_nonzero(grid == 1)
total_number_spin_up = np.append(total_number_spin_up,number_of_spin_up)
total_number_spin_down = np.append(total_number_spin_down, pow(N,2)-number_of_spin_up)
spin_up = total_number_spin_up[-1]
spin_down = total_number_spin_down[-1]
average_spin = (spin_up-spin_down)/N**2
return grid, average_spin
beta = 10
#runs the code to settle it.
average_spin_count = np.array([])
for i in range(300):
grid_2, average_spin = compare_energies(N**2, beta)
average_spin_count = np.append(average_spin_count, average_spin)
y = average_spin_count[-1]
如果你绘制这种情况的最终网格,你会看到会发生什么,以matplotlib
为例,见下文:
import matplotlib.pyplot as plt
plt.imshow(grid)
plt.show()
你会发现 space 被分成了两个区域。或者,您可以如下初始化网格而不是随机数。
grid = np.zeros((N, N))
grid[:N//2] = 1
您将看到类似的行为。解决方法很简单。如果您计算边界处自旋翻转的能量和相应的概率,您会发现能量值为 -3,导致概率 9.76e-27
,对于给定的 beta 基本上是 0
。因此,这种状态非常稳定,300 次迭代内你可能看不到任何变化。