【问题标题】:How to prevent odeint from giving me solutions that blow up如何防止 odeint 给我解决方案
【发布时间】:2021-11-20 02:12:17
【问题描述】:

我正在尝试使用 Scipy 的 odeint 使用不同的初始条件来求解和绘制 ODE。这是在下面的代码中完成的。请注意,对于三个初始条件(2、4 和 6),解决方案消失了,然后对于这 3 个解决方案,图表开始看起来很奇怪(在图中,最值得注意的是 ic/N0 = 6,它对应于绿色曲线,但您也可以在底部的边缘看到一些蓝色和橙色)。我该如何解决这个问题,以便对于那些最终会消失的解决方案,我只是得到这些曲线,之后没有奇怪的行为?显然,这样做的一种方法是根据解决方案从正变为负的时间停止绘制曲线,但我想知道是否有更优雅的方法来做到这一点。

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
ic = [2,4,6,8,10,12,14,16,18,20]
def de(t, u):
    return u*(1-u/12)-4*np.heaviside(-(t-5), 1)

plt.xlim([0, 10])
plt.ylim([0, 20])
for N0 in ic:
    N1 = odeint(de, N0, np.linspace(0, 10, 10000), tfirst=True)
    plt.plot(np.linspace(0,10,10000), N1)

编辑: 这是解决此问题的一种不太优雅的方法:

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

plt.xlim([0, 10])
plt.ylim([0, 20])
for N0 in ic:
    N1 = odeint(de, N0, np.linspace(0, 10, 10000), tfirst=True)
    plt.plot(np.linspace(0,10,10000), N1)
for N0 in ic_to_zero[0:1]:
    N1 = odeint(de, N0, np.linspace(0, 2, 10000), tfirst=True)
    plt.plot(np.linspace(0,2,10000), N1)
for N0 in ic_to_zero[1:2]:
    N1 = odeint(de, N0, np.linspace(0, 2, 10000), tfirst=True)
    plt.plot(np.linspace(0,2,10000), N1)
for N0 in ic_to_zero[2:3]:
    N1 = odeint(de, N0, np.linspace(0, 4, 10000), tfirst=True)
    plt.plot(np.linspace(0,4,10000), N1)

编辑:我第一次尝试和asked 讨论如何使用solve_ivp 解决这个问题,但事情变得更加复杂

【问题讨论】:

  • 只是猜测:使用重边函数会导致函数不平滑,因此求解器在 t=5 时行为不端
  • @Tarik 对,但这并不妨碍它正确绘制具有不同初始条件的其他解决方案
  • 也许你可以尝试不同的 scipy ode 求解器。
  • @Tarik 实际上我第一次尝试使用solve_ivp,但它让事情变得更加复杂:stackoverflow.com/questions/69352999/…
  • 等等,似乎低于零的解决方案都在爆炸。为什么不独立解决从 0 到 5 然后从 5 到 10 的问题?

标签: python scipy differential-equations


【解决方案1】:

由于您对负值范围不感兴趣,所以让我们在 u 的某个负值处切断 ODE 函数。一般来说,右侧有界或线性增长的 ODE 始终存在,并且在数值上也是良性的。

ic = [2,4,6,8,10,12,14,16,18,20]
def de(t, u):
    u = max(-10,u) # replace f(t,u) with f(t,-10) for u<-10
    return u*(1-u/12)-4*np.heaviside(-(t-5), 1)

plt.xlim([0, 10])
plt.ylim([0, 20])
t_plot = np.linspace(0, 10, 10000)
for N0 in ic:
    N1 = odeint(de, N0, t_plot, tfirst=True)
    plt.plot(t_plot, N1)

此结果在情节中没有任何其他变化

【讨论】:

  • 非常感谢。你能解释一下为什么你把u=max(-10, u)放在你放的地方吗?我知道您提到线性有界 RHS 在数值上是良性的,但我的问题是:当 odeint 调用 de 时,似乎基于您的解决方案,它使用特定值 u 调用它。这个值代表什么?
  • 如果大于-10,它使u 保持不变,因此在绘图的可见部分中没有任何变化。请注意,在u==-10,导数是负数,因此不会有“返回”解决方案。该值在很大程度上是任意的,您也可以使用-1-50,只要安全地远离该区域即可。
【解决方案2】:

我相信在这种情况下Lutz Lehmann's solution 更好。但是由于我已经对其进行了编码,因此我发布了我的解决方案,该解决方案在积分曲线超出范围后也会停止。也许这对有一天来这个帖子的人有用。

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

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

for N0 in ic:
    # supressing ODEintWarning
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        N1 = odeint(de, N0, np.linspace(0, 10, 10000), tfirst=True).reshape(-1)
    cond = (0 > N1) | (N1 > 20)
    stop_at = len(N1)-1 if np.all(~cond) else np.argmax(cond)
    plt.plot(np.linspace(0,10,10000)[:stop_at], N1[:stop_at])

【讨论】:

  • 使用solve_ivp可以更直接地使用“事件”机制来实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 2021-10-26
相关资源
最近更新 更多