Search code examples
pythonscipyrunge-kutta

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


from

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

with

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

t_eval is optional for store solution in specify time. Will this override timestep select by RK45?


Solution

  • It does not override the timestep. One way to verify this is to use dense_output=True, which saves data at each timestep for interpolating later.

    The sol attribute contains additional information about the timesteps in the ts attribute. Here, you can see that using t_eval changes the return of sol3.t but does not affect the timesteps.

    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.  ]
    

    I mildly suggest that instead of using t_eval, you should only use dense_output=True and then construct y_eval after the fact. This is a much more flexible and transparent usage.

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