Python 访问Scipy ode解算器';内部步骤

Python 访问Scipy ode解算器';内部步骤,python,scipy,ode,Python,Scipy,Ode,我目前正在为一个涉及求解微分方程的项目从MATLAB切换到Python 在MATLAB中,如果传递的t数组仅包含两个元素,则解算器输出模拟的所有中间步骤。然而,在Python中,您只获得了起点和终点。要获得两者之间的时间点,必须明确指定所需的时间点 from scipy import integrate as sp_int import numpy as np def odeFun(t,y): k = np.ones((2)) dy_dt = np.zeros(y.shape)

我目前正在为一个涉及求解微分方程的项目从MATLAB切换到Python

在MATLAB中,如果传递的t数组仅包含两个元素,则解算器输出模拟的所有中间步骤。然而,在Python中,您只获得了起点和终点。要获得两者之间的时间点,必须明确指定所需的时间点

from scipy import integrate as sp_int
import numpy as np

def odeFun(t,y):
    k = np.ones((2))
    dy_dt = np.zeros(y.shape)
    dy_dt[0]= k[1]*y[1]-k[0]*y[0]
    dy_dt[1]=-dy_dt[0]
    return(dy_dt)

t = np.linspace(0,10,1000)
yOut = sp_int.odeint(odeFun,[1,0],t)
我还研究了以下方法:

solver = sp_int.ode(odefun).set_integrator('vode', method='bdf')
solver.set_initial_value([1,0],0)
dt = 0.01
solver.integrate(solver.t+dt)
但是,它仍然需要显式的
dt
。通过阅读,我了解到Python的解算器(例如,
'vode'
)为请求的
dt
计算中间步骤,然后插值该时间点并输出它。我想直接得到所有这些中间步骤,而不需要插值。这是因为它们代表了在积分公差范围内完整描述时间序列所需的最小点数

有没有这样的选择

我在Python 3中工作。

scipy.integrate.odeint
odeint
有一个选项
full\u output
,允许您获取包含集成信息的字典,包括
tcur
,它是:

每个时间步达到的t值的向量。(始终至少与输入时间一样大)

(请注意第二句话:实际步骤始终与所需输出一样精细。如果要使用最少数量的必要步骤,必须要求进行粗略采样。)

现在,这并没有给出值,但我们可以通过使用以下步骤进行第二次积分来获得这些值:

from scipy.integrate import odeint
import numpy as np

def f(y,t):
    return np.array([y[1]-y[0],y[0]-y[1]])

start,end = 0,10 # time range we want to integrate
y0 = [1,0]       # initial conditions

# Function to add the initial time and the target time if needed:
def ensure_start_and_end(times):
    times = np.insert(times,0,start)
    if times[-1] < end:
        times = np.append(times,end)
    return times

# First run to establish the steps
first_times = np.linspace(start,end,100)
first_run   = odeint(f,y0,first_times,full_output=True)
first_steps = np.unique(first_run[1]["tcur"])

# Second run to obtain the results at the steps
second_times = ensure_start_and_end(first_steps)
second_run   = odeint(f,y0,second_times,full_output=True,h0=second_times[0])
second_steps = np.unique(second_run[1]["tcur"])

# ensuring that the second run actually uses (almost) the same steps.
np.testing.assert_allclose(first_steps,second_steps,rtol=1e-5)

# Your desired output
actual_steps = np.vstack((second_times, second_run[0].T)).T
从scipy.integrate导入odeint
将numpy作为np导入
def f(y,t):
返回np.array([y[1]-y[0],y[0]-y[1]])
开始,结束=0,10#我们要集成的时间范围
y0=[1,0]#初始条件
#用于添加初始时间和目标时间(如果需要)的函数:
def确保开始和结束(次数):
times=np.insert(times,0,start)
如果时间[-1]<结束:
times=np.append(times,end)
返回时间
#首先运行以建立步骤
first_times=np.linspace(开始、结束、100)
第一次运行=odeint(f,y0,第一次运行次数,完整输出=True)
第一步=np.unique(第一步运行[1][“tcur”])
#第二次运行以获得步骤中的结果
第二次=确保开始和结束(第一步)
第二次运行=odeint(f,y0,第二次运行次数,完整输出=True,h0=第二次运行次数[0])
第二步=np.unique(第二步运行[1][“tcur”])
#确保第二次运行实际使用(几乎)相同的步骤。
np.测试.断言所有关闭(第一步,第二步,rtol=1e-5)
#您想要的输出
实际步数=np.vstack((第二次,第二次运行[0].T)).T
scipy.integrate.ode

我对本模块有一定的经验,我不知道有什么方法可以在不深入挖掘内部的情况下获得步长。

“然后插值该时间点并输出它”你确定吗?听起来有点不寻常。正常的程序是缩短会超调的第一步,使其达到要求的点We’你正在掌握时间进度。如果你真的很绝望,你总是可以仪器化被积函数并记录调用它的t。@PaulPanzer:对于某些方法来说,插值是非常常见的,在这些方法中,可以假设插值足够精确,缩短时间步长会相当单调乏味
scipy.integrate.odeint
插值,从
tcur
数据(请参见我的答案)以及您建议的日志记录中可以看出–两者都不包含初始时间步长。@PaulPanzer:如果您真的非常绝望,您可以随时插入被积函数并记录调用它的t。–这不会给您提供所需的结果,因为许多解算器还需要在步骤之间计算导数(
odeFun
),例如,给出一个简单的示例。这是因为它们表示完整描述积分公差内的时间序列所需的最小点数你能详细说明你为什么需要这些信息吗?我感觉到了一种感觉。@Wrzlprmft哇,即使按照我的标准,在一条评论中也有很多错误的陈述。谢谢你把它们调整好。