指定时间评估是否会通过 RK45 方法覆盖时间步长 select? (scipy.integrate.solve_ivp)

will specifying time evaluate will override timestep select by RK45 method? (scipy.integrate.solve_ivp)

来自

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html

sol = scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)

t_eval是可选的,用于指定时间的商店解决方案。 这会通过 RK45 覆盖时间步长 select 吗?

它不会覆盖时间步长。验证这一点的一种方法是使用 dense_output=True,它在每个时间步保存数据以供稍后插值。

sol 属性包含有关 ts 属性中时间步长的附加信息。在这里,您可以看到使用 t_eval 会更改 sol3.t 的 return 但不会影响时间步长。

import numpy as np
from scipy.integrate import solve_ivp

# To make readable
np.set_printoptions(precision=2)

method = 'RK45'

def dy(t, y):
    return y

sol = solve_ivp(dy, (0, 10), [1], method=method)
print(f"No options    : {sol.t}")
sol2 = solve_ivp(dy, (0, 10), [1], method=method, dense_output=True)
print(f"Dense output  : {sol2.t}")
print(f"  Interpolants: {sol2.sol.ts}")
t_eval = [5]
sol3 = solve_ivp(dy, (0, 10), [1], method=method, t_eval=t_eval, dense_output=True)
print(f"t_eval return : {sol3.t}")
print(f"  Interpolants: {sol3.sol.ts}")

returns

No options    : [ 0.    0.1   1.07  2.3   3.65  5.03  6.43  7.83  9.24 10.  ]
Dense output  : [ 0.    0.1   1.07  2.3   3.65  5.03  6.43  7.83  9.24 10.  ]
  Interpolants: [ 0.    0.1   1.07  2.3   3.65  5.03  6.43  7.83  9.24 10.  ]
t_eval return : [5]
  Interpolants: [ 0.    0.1   1.07  2.3   3.65  5.03  6.43  7.83  9.24 10.  ]

我温和地建议您不要使用 t_eval,您应该只使用 dense_output=True,然后在事后构造 y_eval。这是一种更加灵活和透明的用法。

sol = solve_ivp(dy, (0, 10), [1], method=method, dense_output=True)
y_eval = sol.sol(t_eval)

简答

,不!它不会覆盖 RK45 的时间步长,因为函数 scipy.integrate.solve_ivp 将为 t_eval 中的每个 t 使用内插值。而RK45依旧使用自己的时间步


长答案。

经过一番调查,我发现了这一点。 根据 source code!

在函数 solve_ivp 的第 156 行。在第 477 行。

solver = method(fun, t0, y0, tf, vectorized=vectorized, **options)

求解器不将t_eval作为参数。 在第 511 行。

t = solver.t

求解器 return 它拥有 t.

第 545 行。

if solver.direction > 0:
            t_eval_i_new = np.searchsorted(t_eval, t, side='right')
            t_eval_step = t_eval[t_eval_i:t_eval_i_new]

t_eval_i_newt_eval 的新索引,在使用 np.searchsortedt_eval_step 之间有 tt_eval 的时间步长在 ode 求解器步骤之间。

if t_eval_step.size > 0:
            if sol is None:
                sol = solver.dense_output()
            ts.append(t_eval_step)
            ys.append(sol(t_eval_step))
            t_eval_i = t_eval_i_new

这意味着我们将 t_eval_step 附加到 ts 并使用 solver.dense_output() 对步长进行插值并给出 t_eval_step 中每个特定时间的近似值 在第 585 行完成积分后,程序 return 输出 .

 return OdeResult(t=ts, y=ys, sol=sol, t_events=t_events, nfev=solver.nfev,
                 njev=solver.njev, nlu=solver.nlu, status=status,
                 message=message, success=status >= 0)