来自scipy的solve_ivp不会整合tspan的整个范围

8mmmxcuj  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(203)

我试图在Python中使用scipy中的solve_ivp来求解IVP。我将solve_ivptspan参数指定为(0,10),如下所示。然而,由于某种原因,我得到的解总是在t=2.5附近停止。

from scipy.integrate import solve_ivp
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as optim

def dudt(t, u):
    return u*(1-u/12)-4*np.heaviside(-(t-5), 1)

ic = [2,4,6,8,10,12,14,16,18,20]

sol = solve_ivp(dudt, (0, 10), ic, t_eval=np.linspace(0, 10, 10000))

for solution in sol.y:
    y = [y for y in solution if y >= 0]
    t = sol.t[:len(y)]
    plt.plot(t, y)

0ejtzxu1

0ejtzxu11#

哪里出了问题

您应该始终查看求解程序返回的内容。在本例中,它给出了
消息:“所需的步长小于数字之间的间距。”
把求解scipy.integrate.solve_ivp初值问题的过程想象成反复估计一个方向,然后朝那个方向前进一小步,上述误差意味着方程的解变化太快,采用尽可能小的步长太远了。但是你的方程足够简单,至少对于t =< 5,其中4*np.heaviside(-(t-5), 1)总是得到4,它可以精确地/象征性地解出来。

符号解决方案

Sympy可以解微分方程。虽然你可以给它一个初始值,但对每个初始值解一次要花更长的时间。因此,我告诉它给予我所有的解,然后我分别计算初始值的参数C1

import numpy as np
import matplotlib.pyplot as plt
from sympy import *

ics = [2,4,6,8,10,12,14,16,18,20]

f = symbols("f", cls=Function)
t = symbols("t")
eq = Eq(f(t).diff(t),f(t)*(1-f(t)/12)-4)
base_sol = dsolve(eq)
c1s = [solve(base_sol.args[1].subs({t:0})-ic) for ic in ics]

# Apparently sympy is unhappy that numpy does not supply a cotangent.

# So I do that manually.

sols = [lambdify(t, base_sol.args[1].subs({symbols('C1'):C1[0]}), 
modules=['numpy', {'cot':lambda x:1/np.tan(x)}]) for C1 in c1s]
t = np.linspace(0, 5, 10000)

for sol in sols:
    y = sol(t)
    mask = (y > -5) & (y < 20)
    plt.plot(t[mask], y[mask])

乍一看,这幅图看起来很奇怪。特别是蓝色和橙子的直线部分。这只是因为值位于掩码范围之外,所以matplotlib直接将它们连接起来。实际上发生的是一个突然的跳跃。这个跳跃提前提示了数值模式求解器。当你让sympy打印第一个解时,你可以看得更清楚。

已知切线在pi/4处有一个跳跃,如果你解出上面的切线的自变量,你会得到2.47241377386575,这可能是你的绘图停止的地方。

那么t>5又是什么呢?

不幸的是,你的方程在t=5上是不连续的。一种方法是分别解t>5的方程,初始值由第一个方程的解给出。但这是另一个问题。

相关问题