python - 我的代码在超过 15500 次迭代时突然停止编写
问题描述
我正在研究如何用 Python 编写代码,并且正在尝试重新创建我在大学时编写的代码。
该代码基于应用于流行病学的 2D Ising 模型。它的作用是:
- 它使用 numpy 构造一个 2D 100x100 数组,并为每个元素分配一个值 -1。
calc_h
能量是根据下面脚本中的函数计算的。- 然后,代码从晶格中随机选择一个单元,将值更改为 1,然后再次计算系统的能量。
- 然后,代码比较系统的能量是否小于或等于先前的配置。如果是,它“接受”更改。如果不是,则将概率与随机数进行比较以确定更改是否被“接受”。这部分在
metropolis
函数中完成。 - 代码使用 while 循环重复该过程,直到达到指定的最大迭代次数
max_iterations
。- 代码计算函数中具有 -1 值(即s
变量)的元素数量和具有 1 值(即i
变量)的元素数量countSI
。该脚本每 500 次迭代附加到一个文本文件。
问题
我运行了脚本,除了执行时间太长外,计数停止在 15500。代码没有抛出任何错误,但它一直在继续。我等了大约 3 个小时才完成,但它仍然只能进行 15500 次迭代。
我尝试将写入 csv 块的内容注释掉,而是先打印值以观察它的发生情况,然后我看到,它再次停在 15500 处。
我不知道出了什么问题,因为它不会引发任何错误,而且代码也不会停止。
这是整个脚本。我在每个块下面描述了该部分的作用:
import numpy as np
import random as r
import math as m
import csv
init_size = input("Input array size: ")
size = int(init_size)
这部分初始化二维数组的大小。出于观察目的,我选择了一个 100 x 100 的格子。
def check_overflow(indx, size):
if indx == size - 1:
return -indx
else:
return 1
我使用这个函数
calc_h
来初始化一个圆形边界条件。简单地说,晶格的边缘是相互连接的。
def calc_h(pop, J1, size):
h_sum = 0
r = 0
c = 0
while r < size:
buffr = check_overflow(r, size)
while c < size:
buffc = check_overflow(c, size)
h_sum = h_sum + J1*pop[r,c] * pop[r,c-1] * pop[r-1,c] * pop[r+buffr,c] * pop[r,c+buffc]
c = c + 1
c = 0
r = r + 1
return h_sum
此函数通过将单元格的值与其顶部、底部、左侧和右侧邻居的乘积之和乘以一个常数来计算系统的能量
J
。
def metropolis(h, h0, T_):
if h <= h0:
return 1
else:
rand_h = r.random()
p = m.exp(-(h - h0)/T_)
if rand_h <= p:
return 1
else:
return 0
这决定是否接受从 -1 到 1 的更改,具体取决于
calc_h
得到的内容。
def countSI(pop, sz, iter):
s = np.count_nonzero(pop == -1)
i = np.count_nonzero(pop == 1)
row = [iter, s, i]
with open('data.txt', 'a') as si_csv:
tally_data = csv.writer(si_csv)
tally_data.writerow(row)
si_csv.seek(0)
这部分计算了晶格中 -1 和 1 的数量。
def main():
J = 1
T = 4.0
max_iterations = 150000
population = np.full((size, size), -1, np.int8) #initialize population array
二维数组在 中初始化
population
。
h_0 = calc_h(population, J, size)
turn = 1
while turn <= max_iterations:
inf_x = r.randint(1,size) - 1
inf_y = r.randint(1,size) - 1
while population[inf_x,inf_y] == 1:
inf_x = r.randint(1,size) - 1
inf_y = r.randint(1,size) - 1
population[inf_x, inf_y] = 1
h = calc_h(population, J, size)
accept_i = metropolis(h,h_0,T)
这是主循环,其中随机选择一个单元格,是否接受更改由函数确定
metropolis
。
if (accept_i == 0):
population[inf_x, inf_y] = -1
if turn%500 == 0 :
countSI(population, size, turn)
该脚本每 500 次迭代计数一次。
turn = turn + 1
h_0 = h
main()
预期的输出是一个文本文件,其中包含每 500 次迭代的s
次数i
。看起来像这样的东西:
500,9736,264
1000,9472,528
1500,9197,803
2000,8913,1087
2500,8611,1389
3000,8292,1708
3500,7968,2032
4000,7643,2357
4500,7312,2688
5000,6960,3040
5500,6613,3387
6000,6257,3743
6500,5913,4087
7000,5570,4430
7500,5212,4788
我不知道从哪里开始解决方案。起初,我认为是对 csv 的写入导致了问题,但通过 print 函数进行探测证明并非如此。我尽量让它简洁。
我希望你们能帮忙!我真的很想学习这门语言并开始模拟很多东西,我认为这个迷你项目对我来说是一个很好的开始。
非常感谢!
解决方案
推荐阅读
- c++ - 无法理解 C++ 指针语法
- reactjs - 我可以在客户端使用 Axios 或 Fetch 调用 Twitter API 吗?
- c# - 从多继承类中调用所有“基”类的更新、启动等的有效方法?
- android - 当游戏是 64 位时,Google Play 控制台 64 位错误
- oracle - 通过引用共享(对象类型)实例
- xamarin.forms - Xamarin.Plugin.Calender 禁用日期
- python - 如何在Python中逐步迭代地叠加绘图?
- c# - 如何在 gRPC 服务器上关闭 HTTPS
- sql - 将两个选择表达式与左连接结合起来
- c# - 如何使用 dtsearch 检索 eml 文件的电子邮件正文和附件文本?