使用 odeint 求解带有阶跃函数参数的 ODE 集
Solving ODE set with a step-function parameter using odeint
我正在尝试用 Python 中的 odeint 对以下系统进行数值求解::
我的问题是 k1 取决于 p 的值。当 p<=0.01
k1=0
否则 k1=5
.
我不确定如何编写具有上述约束的系统。我可以开始:
def sys(x,t,flip):
S,T,p = x
dx = [1-T-k1*T,
0.1*(1-S)-k1*S,
-0.2*(1-T-k1*T)+0.1*(1-S)-k1*S]
return dx
其中 flip
可以是 0.01
值,但我不确定如何为这种情况实现 if 语句,因为我需要集成过程来检查 [= 的值16=] 每次迭代后。
这是一个使用 solve_ivp 的解决方案:
import numpy as np
import matplotlib.pylab as plt
from scipy.integrate import solve_ivp
def ode(t, TS):
T, S = TS
p = -0.2*T + S
k1 = 0 if p <= 0.01 else 5
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
# Solve
TS_start = (0.7, 0.4)
t_span = [0, 3]
sol = solve_ivp(ode, t_span, TS_start, method='RK45',
rtol=1e-5)
print(sol.message)
print('nbr eval', sol.nfev)
# Graph
plt.plot(sol.t, sol.y[0, :], label='T')
plt.plot(sol.t, sol.y[1, :], label='S'); plt.legend();
plt.xlabel('time');
这似乎是一个很难用数值求解的问题。其他测试的求解器不收敛,使用事件也没有帮助,因为它们在稳态解附近越来越频繁
编辑:确实将翻转值更改为 -0.01 而不是 +0.01 会导致极限循环解决方案,solve_ivp
的 events
方法正在运行:
import numpy as np
import matplotlib.pylab as plt
from scipy.integrate import solve_ivp
def ode(t, TS):
T, S = TS
p = -0.2*T + S
k1 = 0 if sign_change(t, TS) <= 0 else 5
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
def sign_change(t, TS):
T, S = TS
p = -0.2*T + S
flip = -0.01
return p - flip
# Solve
TS_start = [0.3, 0.1]
t_span = [0, 5]
sol = solve_ivp(ode, t_span, TS_start,
method='RK45', events=sign_change)
print(sol.message)
print('nbr eval', sol.nfev)
# Graph
plt.plot(sol.t, sol.y[0, :], '-x', label='T')
plt.plot(sol.t, sol.y[1, :], label='S'); plt.legend();
plt.xlabel('time');
for t in sol.t_events[0]:
plt.axvline(x=t, color='gray', linewidth=1)
现在的解决方案是:
要在积分后重建 k1
和 p
的值,将此计算放入一个额外的函数中
def kp(T,S):
p = -0.2*T + S
k1lo, k1hi = 0, 5
flip = -0.01
k1 = 0.5*(k1lo+k1hi + (k1hi-k1lo)*np.tanh((p-flip)/1e-8))
return k1,p
然后在 ODE 导数函数中调用它
def ode(t, TS):
T, S = TS
k1,_ = kp(T,S)
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
积分后沿解分量绘制
T,S = sol.y;
k,p = k1(T,S);
使用每个评论修正的阈值 flip=-0.01
确实获得了振荡行为。
我正在尝试用 Python 中的 odeint 对以下系统进行数值求解:
我的问题是 k1 取决于 p 的值。当 p<=0.01
k1=0
否则 k1=5
.
我不确定如何编写具有上述约束的系统。我可以开始:
def sys(x,t,flip):
S,T,p = x
dx = [1-T-k1*T,
0.1*(1-S)-k1*S,
-0.2*(1-T-k1*T)+0.1*(1-S)-k1*S]
return dx
其中 flip
可以是 0.01
值,但我不确定如何为这种情况实现 if 语句,因为我需要集成过程来检查 [= 的值16=] 每次迭代后。
这是一个使用 solve_ivp 的解决方案:
import numpy as np
import matplotlib.pylab as plt
from scipy.integrate import solve_ivp
def ode(t, TS):
T, S = TS
p = -0.2*T + S
k1 = 0 if p <= 0.01 else 5
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
# Solve
TS_start = (0.7, 0.4)
t_span = [0, 3]
sol = solve_ivp(ode, t_span, TS_start, method='RK45',
rtol=1e-5)
print(sol.message)
print('nbr eval', sol.nfev)
# Graph
plt.plot(sol.t, sol.y[0, :], label='T')
plt.plot(sol.t, sol.y[1, :], label='S'); plt.legend();
plt.xlabel('time');
这似乎是一个很难用数值求解的问题。其他测试的求解器不收敛,使用事件也没有帮助,因为它们在稳态解附近越来越频繁
编辑:确实将翻转值更改为 -0.01 而不是 +0.01 会导致极限循环解决方案,solve_ivp
的 events
方法正在运行:
import numpy as np
import matplotlib.pylab as plt
from scipy.integrate import solve_ivp
def ode(t, TS):
T, S = TS
p = -0.2*T + S
k1 = 0 if sign_change(t, TS) <= 0 else 5
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
def sign_change(t, TS):
T, S = TS
p = -0.2*T + S
flip = -0.01
return p - flip
# Solve
TS_start = [0.3, 0.1]
t_span = [0, 5]
sol = solve_ivp(ode, t_span, TS_start,
method='RK45', events=sign_change)
print(sol.message)
print('nbr eval', sol.nfev)
# Graph
plt.plot(sol.t, sol.y[0, :], '-x', label='T')
plt.plot(sol.t, sol.y[1, :], label='S'); plt.legend();
plt.xlabel('time');
for t in sol.t_events[0]:
plt.axvline(x=t, color='gray', linewidth=1)
现在的解决方案是:
要在积分后重建 k1
和 p
的值,将此计算放入一个额外的函数中
def kp(T,S):
p = -0.2*T + S
k1lo, k1hi = 0, 5
flip = -0.01
k1 = 0.5*(k1lo+k1hi + (k1hi-k1lo)*np.tanh((p-flip)/1e-8))
return k1,p
然后在 ODE 导数函数中调用它
def ode(t, TS):
T, S = TS
k1,_ = kp(T,S)
dTdt = 1 - T - k1*T
dSdt = 0.1*(1 - S) - k1*S
return dTdt, dSdt
积分后沿解分量绘制
T,S = sol.y;
k,p = k1(T,S);
使用每个评论修正的阈值 flip=-0.01
确实获得了振荡行为。