Передайте args для solve_ivp (новый API-интерфейс SciPy ODE)

Для решения простых ODE с помощью SciPy я использовал функцию odeint с формой:

scipy.integrate.odeint(func, y0, t, args=(), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0)[source]

где простая интегрируемая функция может включать дополнительные аргументы в форме:

def dy_dt(t, y, arg1, arg2):
    # processing code here

В SciPy 1.0 кажется, что функции ode и odeint были заменены более новым методом solve_ivp.

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

Однако, похоже, что здесь нет ни параметра args, ни каких-либо указаний в документации на реализацию передачи аргументов.

Поэтому мне интересно, возможна ли передача аргументов с помощью нового API, или эта функция еще не добавлена? (Мне показалось бы упущением, если бы эти функции были намеренно удалены?)

Ссылка: https://docs.scipy.org/doc/scipy/reference/integrate.html

Ответ 1

Кажется, что новая функция не имеет параметра args. В качестве обходного пути вы можете создать обертку, например

def wrapper(t, y):
    orig_func(t,y,hardcoded_args)

и передать это.

Ответ 2

Относительно недавно появился похожий вопрос о scipy github. Их решение заключается в использовании lambda:

solve_ivp(fun=lambda t, y: fun(t, y, *args), ...)

И они утверждают, что накладных расходов уже достаточно, чтобы это не имело значения.

Ответ 4

В добавление к ответу Клеба приведен пример использования метода lambda t,y: fun(t,y,args). Мы установили дескриптор функции, который возвращает rhs однородного ODE второго порядка с двумя параметрами. Затем мы передаем его нашему решателю вместе с несколькими вариантами.

import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt


def rhs_2nd_order_ode(t, y, a, b):
    """
    2nd order ODE function handle for use with scipy.integrate.solve_ivp
    Solves u'' + au'+ bu = 0 after reducing order with y[0]=u and y[1]=u'.

    :param t: dependent variable
    :param y: independent variables
    :param a: a
    :param b: b
    :return: Returns the rhs of y[0]' = y[1] and y[1]' = -a*y[1] - b*y[0]
    """
    return [y[1], -a*y[1] - b*y[0]]


if __name__ == "__main__":
    t_span = (0, 10)
    t_eval = np.linspace(t_span[0], t_span[1], 100)
    y0 = [0, 1]
    a = 1
    b = 2
    sol = integrate.solve_ivp(lambda t,y: rhs_2nd_order_ode(t,y,a,b), t_span, y0, 
                              method='RK45', t_eval=t_eval)

    fig, ax = plt.subplots(1, 1)
    ax.plot(sol.t, sol.y[0])
    ax.set(xlabel='t',ylabel='y')

Ответ 5

Для полноты, я думаю, что вы также можете сделать это, но я не уверен, почему вы будете беспокоиться о двух других опциях, опубликованных здесь, которые выглядят идеально.

from functools import partial
fun = partial(dy_dt, arg1=arg1, arg2=arg2)
scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)