Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 求解隐式常微分方程(微分代数方程)_Python_Scipy_Constraints_Ode_Numerical Integration - Fatal编程技术网

Python 求解隐式常微分方程(微分代数方程)

Python 求解隐式常微分方程(微分代数方程),python,scipy,constraints,ode,numerical-integration,Python,Scipy,Constraints,Ode,Numerical Integration,我正试图用scipy的odeint解一个二阶ODE。我遇到的问题是,函数隐式地耦合到二阶项,如简化的代码片段所示(请忽略示例中的假装物理): 在这种情况下,我意识到隐式变量的代数求解是可能的,但是在我的实际场景中,F\u r和a的计算之间有很多逻辑,代数操作失败 我相信DAE可以使用MATLAB的函数来解决,但如果可能的话,我会尽量避免这种情况 我的问题是——有没有办法用python(最好是scipy)解决隐式ODE函数(DAE)?有没有更好的方法来解决上述问题 作为最后手段,可以接受从上一个时

我正试图用scipy的odeint解一个二阶ODE。我遇到的问题是,函数隐式地耦合到二阶项,如简化的代码片段所示(请忽略示例中的假装物理):

在这种情况下,我意识到隐式变量的代数求解是可能的,但是在我的实际场景中,
F\u r
a
的计算之间有很多逻辑,代数操作失败

我相信DAE可以使用MATLAB的函数来解决,但如果可能的话,我会尽量避免这种情况

我的问题是——有没有办法用python(最好是scipy)解决隐式ODE函数(DAE)?有没有更好的方法来解决上述问题


作为最后手段,可以接受从上一个时间步传递
a
。如何在每个时间步后将
dydt[1]
传递回函数?

如果代数操作失败,您可以在每个时间步执行约束的数值解,例如
fsolve

import sys
from numpy import linspace
from scipy.integrate import odeint
from scipy.optimize import fsolve

y0 = [0, 5]
time = linspace(0., 10., 1000)
F_lon = 10.
mass = 1000.

def F_r(a, v):
    return (((1 - a) / 3) ** 2 + (2 * (1 + a) / 3) ** 2) * v

def constraint(a, v):
    return (F_lon - F_r(a, v)) / mass - a

def integral(y, _):
    v = y[1]
    a, _, ier, mesg = fsolve(constraint, 0, args=[v, ], full_output=True)
    if ier != 1:
        print "I coudn't solve the algebraic constraint, error:\n\n", mesg
        sys.stdout.flush()
    return [v, a]

dydt = odeint(integral, y0, time)
显然,这会减慢你的时间整合。始终检查
fsolve
是否找到了一个好的解决方案,并刷新输出,以便在发生时实现它并停止模拟

关于如何在前一个时间步“缓存”变量的值,您可以利用默认参数仅在函数定义中计算的事实

from numpy import linspace
from scipy.integrate import odeint

#you can choose a better guess using fsolve instead of 0
def integral(y, _, F_l, M, cache=[0]):
    v, preva = y[1], cache[0]
    #use value for 'a' from the previous timestep
    F_r = (((1 - preva) / 3) ** 2 + (2 * (1 + preva) / 3) ** 2) * v 
    #calculate the new value
    a = (F_l - F_r) / M
    cache[0] = a
    return [v, a]

y0 = [0, 5]
time = linspace(0., 10., 1000)
F_lon = 100.
mass = 1000.

dydt = odeint(integral, y0, time, args=(F_lon, mass))
请注意,为了让技巧发挥作用,
cache
参数必须是可变的,这就是我使用列表的原因。如果您不熟悉默认参数的工作方式,请参阅链接


请注意,这两个代码不会产生相同的结果,为了数值稳定性和精度,在使用前一时间步的值时应该非常小心。第二种方法显然要快得多。

相当古老,但值得更新,因此它可能对任何偶然发现这个问题的人都有用。目前,python中可以解决隐式ODE的软件包非常少。 GEKKO()是其中一个包,专门研究混合整数、非线性优化问题的动态优化,但也可以用作通用DAE解算器

上述“假装物理”问题可以在GEKKO中解决,如下所示

m= GEKKO()
m.time = np.linspace(0,100,101)
F_l = m.Param(value=1000)
mass = m.Param(value =1000)
m.options.IMODE=4
m.options.NODES=3
F_r = m.Var(value=0)
x = m.Var(value=0)
v = m.Var(value=0,lb=0)
a = m.Var(value=5,lb=0)
m.Equation(x.dt() == v)
m.Equation(v.dt() == a)
m.Equation (F_r ==  (((1-a)/3)**2 + (2*(1+a)/3)**2 * v)) 
m.Equation (a == (1000 - F_l)/mass)
m.solve(disp=False)
plt.plot(x)

嗨,谢谢你,弗莱博尔,这里两种解决方案的基本分析给出:
%timeit-odeint(integral1,y0,time)
100个循环,每个循环最好3:9.03毫秒
%timeit-odeint(integral2,y0,time,args=(F_lon,mass))
1000个循环,最佳3:972µs/循环
,第一个例子是
integral1
。在这些条件下,两个示例之间的差异相当小(对于1000个时间步,相差10^-7级),但是,改变一些值(例如,F_lon=1000;mass=100),第二种方法失败。因此,我可以忍受时间的惩罚。谢谢。@Shaun_M,9.03ms和972micro s之间的差异是10倍,第一个解决方案的速度慢了10倍对不起,不清楚。我指的是解之间的数值差异。我想说的是,在这种情况下,使用缓存的积分,精度是可以接受的,但稳定性不是。Thanks@Shaun_M感谢您提供了一种解决DAE的有趣方法。您的解决方案是否适用于具有奇异“质量矩阵”的常微分方程问题,如M*du/dt=f(u)?您也可以看看。您好,我想问一下,您是否知道是否有可能解决具有非常系数的二阶隐式问题?例如,以方程$f(x)y'(x)+g(x)y'(x)*y(x)$为例。快速查看文档并不能给我一个明确的答案,我也没有找到一个涵盖这个案例的例子。
m= GEKKO()
m.time = np.linspace(0,100,101)
F_l = m.Param(value=1000)
mass = m.Param(value =1000)
m.options.IMODE=4
m.options.NODES=3
F_r = m.Var(value=0)
x = m.Var(value=0)
v = m.Var(value=0,lb=0)
a = m.Var(value=5,lb=0)
m.Equation(x.dt() == v)
m.Equation(v.dt() == a)
m.Equation (F_r ==  (((1-a)/3)**2 + (2*(1+a)/3)**2 * v)) 
m.Equation (a == (1000 - F_l)/mass)
m.solve(disp=False)
plt.plot(x)