我有一个大型(> 2000方程式)ODE系统,我想用python scipy的odeint来解决。
我有三个问题需要解决(也许我会问3个不同的问题?)。 为简单起见,我将在这里用玩具模型解释它们,但请记住我的系统很大。 假设我有以下ODE系统:
dS/dt = -beta*S
dI/dt = beta*S - gamma*I
dR/dt = gamma*I
有beta = c p I
其中c,p和gamma是我想传递给odeint的参数。
odeint期待这样的文件:
def myODEs(y, t, params):
c,p, gamma = params
beta = c*p
S = y[0]
I = y[1]
R = y[2]
dydt = [-beta*S*I,
beta*S*I - gamma*I,
- gamma*I]
return dydt
然后可以像这样传递给odeint:
myoutput = odeint(myODEs, [1000, 1, 0], np.linspace(0, 100, 50), args = ([c,p,gamma], ))
我在Mathematica中生成了一个文本文件,比如myOdes.txt,其中文件的每一行都对应于我的ODE系统的RHS,所以它看起来像这样
#myODEs.txt
-beta*S*I
beta*S*I - gamma*I
- gamma*I
我的文本文件看起来与odeint期待的相似,但我还没有完全相同。 我有三个主要问题:
我读了this question接近我的问题1和2并试图复制它(我直接为参数设置值,这样我就不必担心上面的第3点):
systemOfEquations = []
with open("myODEs.txt", "r") as fp :
for line in fp :
systemOfEquations.append(line)
def dX_dt(X, t):
vals = dict(S=X[0], I=X[1], R=X[2], t=t)
return [eq for eq in systemOfEquations]
out = odeint(dX_dt, [1000,1,0], np.linspace(0, 1, 5))
但我得到了错误:
odepack.error: Result from function call is not a proper array of floats.
ValueError: could not convert string to float: -((12*0.01/1000)*I*S),
编辑:我将我的代码修改为:
systemOfEquations = []
with open("SIREquationsMathematica2.txt", "r") as fp :
for line in fp :
pattern = regex.compile(r'.+?\s+=\s+(.+?)$')
expressionString = regex.search(pattern, line)
systemOfEquations.append( sympy.sympify( expressionString) )
def dX_dt(X, t):
vals = dict(S=X[0], I=X[1], R=X[2], t=t)
return [eq for eq in systemOfEquations]
out = odeint(dX_dt, [1000,1,0], np.linspace(0, 100, 50), )
这是有效的(我不太了解for循环的前两行正在做什么)。但是,我想更自动地定义变量的过程,我仍然不知道如何使用此解决方案并在文本文件中传递参数。同样,如何在dX_dt函数中定义参数(取决于变量)?
提前致谢!
答案 0 :(得分:0)
这不是一个完整的答案,而是一些观察/问题,但它们太长而无法发表评论。
dX_dt
使用1d数组odeint
和元组y
多次调用{p> t
。您通过t
参数提供args
。 y
由odeint
生成,并随每一步而变化。 dX_dt
应该简化,以便快速运行。
通常,像[eq for eq in systemOfEquations]
这样的表达式可以简化为systemOfEquations
。 [eq for eq...]
没有做任何有意义的事情。但是systemOfEquations
可能需要它。
我建议你打印systemOfEquations
(针对这个小3行的情况),既为了您的利益,也为了我们的利益。您正在使用sympy
将文件中的字符串转换为方程式。我们需要看看它产生了什么。
请注意myODEs
是一个函数,而不是文件。它可以从模块导入,当然这是一个文件。
指向vals = dict(S=X[0], I=X[1], R=X[2], t=t)
的目的是生成sympy
表达式可以使用的字典。更直接(我认为更快)dX_dt
函数看起来像:
def myODEs(y, t, params):
c,p, gamma = params
beta = c*p
dydt = [-beta*y[0]*y[1],
beta*y[0]*y[1] - gamma*y[1],
- gamma*y[1]]
return dydt
我怀疑运行sympy生成的表达式的dX_dt
比这样的“硬编码”慢得多。
我要添加sympy
标记,因为正如所写,这是将文本文件转换为odeint
可以使用的函数的关键。
我倾向于将等式可变性放在t
参数中,而不是列出的同情表达式。
那就是取代:
dydt = [-beta*y[0]*y[1],
beta*y[0]*y[1] - gamma*y[1],
- gamma*y[1]]
类似
arg12=np.array([-beta, beta, 0])
arg1 = np.array([0, -gamma, -gamma])
arg0 = np.array([0,0,0])
dydt = arg12*y[0]*y[1] + arg1*y[1] + arg0*y[0]
一旦这是正确的,那么argxx
定义可以移到dX_dt
之外,并通过args
传递。现在dX_dt
只是一个简单而快速的计算。
这整个sympy
方法可能会正常工作,但我担心在实践中它会很慢。但是,具有sympy
经验的人可能会有其他见解。