我对Python比较陌生,在编写一段生成然后解决微分方程系统的代码时遇到了一些问题。
我这样做的方法是创建一组变量和系数,(x0,x1,...,xn)和(c0,c1,...,cn ) repsectively,在函数 var()的列表中。然后在 EOM1()中构造方程。初始条件以及方程组都在 EOM2()中汇总并使用odeint
求解。
目前下面的代码运行,虽然效率不高我认为是因为odeint
在每次互动时都会运行所有代码(这是我需要修复的其他内容但不是'主要问题!)。
import sympy as sy
from scipy.integrate import odeint
n=2
cn0list = [0.01, 0.05]
xn0list = [0.01, 0.01]
def var():
xnlist=[]
cnlist=[]
for i in range(n+1):
xnlist.append('x{0}'.format(i))
cnlist.append('c{0}'.format(i))
return xnlist, cnlist
def EOM1():
drdtlist=[]
for i in range(n):
cn1=sy.Symbol(var()[1][i])
xn0=sy.Symbol(var()[0][i])
xn1=sy.Symbol(var()[0][i+1])
eom=cn1*xn0*(1.0-xn1)-cn1*xn1-xn1
drdtlist.append(eom)
xi=sy.Symbol(var()[0][0])
xf=sy.Symbol(var()[0][n])
drdtlist[n-1]=drdtlist[n-1].subs(xf,xi)
return drdtlist
def EOM2(xn, t, cn):
x0, x1 = xn
c0, c1 = cn
f = EOM1()
output = []
for part in f:
output.append(part.evalf(subs={'x0':x0, 'x1':x1, 'c0':c0, 'c1':c1}))
return output
abserr = 1.0e-6
relerr = 1.0e-4
stoptime = 10.0
numpoints = 20
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
wsol = odeint(EOM2, xn0list, t, args=(cn0list,), atol=abserr, rtol=relerr)
我的问题是我很难让Python适当地处理Sympy生成的变量。我用这条线来解决这个问题
output.append(part.evalf(subs={'x0':x0, 'x1':x1, 'c0':c0, 'c1':c1}))
在EOM2()中。不幸的是,我不知道如何将此行概括为从 x0 到 xn 以及从 c0 到 cn的变量列表。这同样适用于 EOM2(),
中的早期行 x0, x1 = xn
c0, c1 = cn
换句话说,我将 n 设置为任意数字,Python是否有办法解释每个元素,就像我在上面手动输入的那样?我试过以下
output.append(part.evalf(subs={'x{0}'.format(j):var(n)[0][j], 'c{0}'.format(j):var(n)[1][j]}))
但这会产生错误,导致我首先使用 evalf ,
TypeError: can't convert expression to float
有没有办法做我想做的事情,生成一组 n 方程式然后用odeint
求解?
答案 0 :(得分:3)
您希望使用evalf
来生成与SciPy一起使用的回调,而不是使用sympy.lambdify
。您需要创建一个具有odeint
预期签名的函数,例如:
y, params = sym.symbols('y:3'), sym.symbols('kf kb')
ydot = rhs(y, p=params)
f = sym.lambdify((y, t) + params, ydot)
yout = odeint(f, y0, tout, param_values)
我们在2017年SciPy会议上提供了一个关于({1}}与lambdify
一起使用的教程(其中包括),该材料可在此处获取:http://www.sympy.org/scipy-2017-codegen-tutorial/
如果您愿意使用外部库来处理外部解算器的功能签名,您可能会对我创作的图书馆感兴趣:pyodesys
答案 1 :(得分:1)
如果我理解正确,您希望在SymPy表达式中进行任意数量的替换。这是如何做到的:
n = 10
syms = sy.symbols('x0:{}'.format(n)) # an array of n symbols
expr = sum(syms) # some expression with those symbols
floats = [1/(j+1) for j in range(n)] # numbers to put in
expr.subs({symbol: value for symbol, value in zip(syms, floats)})
在这种情况下,subs的结果是浮点数(不需要evalf)。
请注意,函数symbols
可以通过冒号表示法直接为您创建任意数量的符号。不需要循环。