用Python模拟衰变链
我正在尝试制作一个计算机程序,可以模拟100万个氡-222原子(变成钋-218变成铅-214变成铋-214变成铅-210)的衰变。每个原子在一个单位时间后衰变为钋-218的几率为0.000126。我有一个1000000 m的列表分配给变量Rn,以表示Radon-222。然后,为了确定某个元素是否衰变,我选择一个介于1和1000000之间的随机整数:如果这个数字小于126,Rn[j]的值从0变为1(衰变),我们在列表Po中添加一个0表示钋,等等。所以在1个单位时间之后,我预计在另一个单位时间之后,大约有126个钋原子,我们应该有大约126个额外的钋原子,但其中一些可能已经衰变为铅214 在这种建模中,我们将时间视为一个离散实体 下面是一个代码,它可以工作,但速度相当慢用Python模拟衰变链,python,physics,Python,Physics,我正在尝试制作一个计算机程序,可以模拟100万个氡-222原子(变成钋-218变成铅-214变成铋-214变成铅-210)的衰变。每个原子在一个单位时间后衰变为钋-218的几率为0.000126。我有一个1000000 m的列表分配给变量Rn,以表示Radon-222。然后,为了确定某个元素是否衰变,我选择一个介于1和1000000之间的随机整数:如果这个数字小于126,Rn[j]的值从0变为1(衰变),我们在列表Po中添加一个0表示钋,等等。所以在1个单位时间之后,我预计在另一个单位时间之后,
import random
def one(s):
count=0
for i in range(len(s)):
if s[i]==1:
count+=1
return count
Rn=[1]*1000000
Po=[0]*1000000
Pb214=[0]*1000000
Bi=[0]*1000000
Pb210=[0]*1000000
print([0,1000000,0,0,0,0])
for i in range(1,100):
for j in range(len(Rn)):
rndecay=random.random()
if rndecay<=0.000126:
Rn[j]=2
for j in range(len(Po)):
if Po[j]==1:
podecay=random.random()
if podecay<=0.203:
Po[j]=2
if Rn[j]==2 and Po[j]==0:
Po[j]=1
for j in range(len(Pb214)):
if Pb214[j]==1:
decay214=random.random()
if decay214<=0.0255:
Pb214[j]=2
if Po[j]==2 and Pb214[j]==0:
Pb214[j]=1
for j in range(len(Bi)):
if Bi[j]==1:
bidecay=random.random()
if bidecay<=0.0346:
Bi[j]=2
if Pb214[j]==2 and Bi[j]==0:
Bi[j]=1
for j in range(len(Pb210)):
if Bi[j]==2 and Pb210[j]==0:
Pb210[j]=1
print([i,one(Rn),one(Po),one(Pb214),one(Bi),one(Pb210)])
随机导入
def 1(s):
计数=0
对于范围内的i(len(s)):
如果s[i]==1:
计数+=1
返回计数
Rn=[1]*1000000
采购订单=[0]*1000000
Pb214=[0]*1000000
Bi=[0]*1000000
Pb210=[0]*1000000
打印([01000000,0,0,0,0])
对于范围(1100)内的i:
对于范围内的j(len(Rn)):
rndecay=random.random()
如果你能以不同的方式解决这个问题,我想你会更走运。不要有1000000个元素列表,你能跟踪每个物种的原子数吗
衰变概率为p的n种群中的衰变数遵循具有这些参数的二项分布。许多基本统计数据包允许您生成服从分布的随机数(而不是random.random
使用的统一分布)。因此,您只需要为每个可能的转换提取一个随机值,然后用结果更新计数。这一方法与原职位采用的方法完全相同
下面是一个使用我编的转移概率计数的示例:
from numpy.random import binomial
atoms = {'Rn222': 1000000,
'Po218': 0,
'Pb214': 0,
'Bi214': 0,
'Pb210': 0}
for _ in range(100):
Rn222_Po218 = binomial(atoms['Rn222'], 0.000126)
Po218_Pb214 = binomial(atoms['Po218'], 0.001240)
Pb214_Bi214 = binomial(atoms['Pb214'], 0.003450)
Bi214_Pb210 = binomial(atoms['Bi214'], 0.012046)
atoms['Rn222'] -= Rn222_Po218
atoms['Po218'] += Rn222_Po218
atoms['Po218'] -= Po218_Pb214
atoms['Pb214'] += Po218_Pb214
atoms['Pb214'] -= Pb214_Bi214
atoms['Bi214'] += Pb214_Bi214
atoms['Bi214'] -= Bi214_Pb210
atoms['Pb210'] += Bi214_Pb210
print atoms
编辑以添加示例。
编辑以添加注释中的二项式解释。在这种特殊情况下,@o_o提出的二项式定律确实相关
如果您想保持代码的精神,这里有几种优化方法:
尽量使用python的内置函数。
one(s)
是无用的,因为它可以完成工作
限制循环的数量。
对于j in…
有5个循环,但一个就足够了
elif
而不是if
使用elif
可以避免一些无用的检查import random
def doit(step,at):
global Rn,Po,Pb214,Bi,Pb210
print([0,1000000,0,0,0,0])
for i in step:
compute(at,Rn,Po,Pb214,Bi,Pb210)
print([i,Rn.count(1),Po.count(1),Pb214.count(1),Bi.count(1),Pb210.count(1)])
def compute(at,Rn,Po,Pb214,Bi,Pb210):
for j in at:
if random.random()<=0.000126:
Rn[j]=2
if Po[j]==1 and random.random()<=0.203:
Po[j]=2
elif Rn[j]==2 and Po[j]==0:
Po[j]=1
if Pb214[j]==1 and random.random()<=0.0255:
Pb214[j]=2
elif Po[j]==2 and Pb214[j]==0:
Pb214[j]=1
if Bi[j]==1 and random.random()<=0.0346:
Bi[j]=2
elif Pb214[j]==2 and Bi[j]==0:
Bi[j]=1
if Bi[j]==2 and Pb210[j]==0:
Pb210[j]=1
N = 1000000
Rn =[1]*N
Po =[0]*N
Pb214=[0]*N
Bi =[0]*N
Pb210=[0]*N
step = range(1,100)
at = range(N)
doit(step,at)
随机导入
def doit(步骤,at):
全球注册护士、采购订单、Pb214、Bi、Pb210
打印([01000000,0,0,0,0])
对于第i步:
计算(at、Rn、Po、Pb214、Bi、Pb210)
打印([i,注册计数(1),采购计数(1),Pb214计数(1),Bi计数(1),Pb210计数(1)])
def计算(at、Rn、Po、Pb214、Bi、Pb210):
对于j in at:
如果随机。随机()谢谢大家的帮助!我已经能够想出这个代码,它使用了一个简单的计数,并且运行得非常好:
import random
radon=1000000
polonium=0
lead214=0
bismuth=0
lead210=0
for t in range(1,100):
for i in range(bismuth):
pdecay=random.random()
if pdecay<0.0346:
bismuth-=1
lead210+=1
for i in range(lead214):
pdecay=random.random()
if pdecay<0.0255:
lead214-=1
bismuth+=1
for i in range(polonium):
pdecay=random.random()
if pdecay<0.203:
polonium-=1
lead214+=1
for i in range(radon):
pdecay=random.random()
if pdecay<0.000126:
radon-=1
polonium+=1
print([t,radon,polonium,lead214,bismuth,lead210])
随机导入
氡=1000000
钋=0
铅214=0
铋=0
铅210=0
对于范围(1100)内的t:
对于范围内的i(铋):
pdecay=random.random()
如果pdecayDon在模拟期间未打印。打印速度很慢,对one
的五次调用也很慢,因为它们每次迭代超过一百万个元素。为什么有数百万个相同的元素而不是计数?@Basic我想模拟现实生活中的随机性,每个“原子”都有一个随机概率(不是完全随机的,而是在给定概率附近)腐烂的迹象。我不知道计数是怎么做到的?@jlammy它遵循二项分布,请看我的回答:)@jlammy好吧,你应该执行相同的检查,除了不是迭代一百万个元素的列表,而是从一百万迭代到一百万,然后计算衰减的数。然后更新(旧状态)计数以减去该数字并将其添加到(新状态)计数。您正在执行相同的检查(字面意思),但您只是节省了一整块内存。当然,你也可以对整个集合中的衰变次数进行近似,得到不可区分的结果,但这显然不太“现实”,我加了一个例子;希望这会有所帮助。