Как ввести временные шаги в scipy.integrate.RK45

Реализация scipy.integrate.RK45 не указывает, где указывать время, в которое должна выполняться интеграция.

Параметр ввода "t_bound" кажется последней эпохой.

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

По сравнению с другим интегратором: scipy.integrate.solve_ivp, у которого есть опция «t_eval», где можно указать все эпохи (в виде массива), где требуется решение.

Работает следующий код:

check=solve_ivp(fun_integrator, t_span, y0, \
             method='RK45', t_eval=t, max_step=1800, rtol=10**(-11), atol=10**(-12))

с «fun_integrator» в качестве моей функции с вводом (t, y) t_span = [0 max (t)] и

t = np.linspace(0,0+0.3*(pts-1)*86400,20)

^= эпохи, в которые нужен ответ

Однако Matlab ode113 дает лучшие результаты, чем scipysolve_ivp, поэтому я хотел попробовать scipy.integrate.RK45, чтобы проверить, получаю ли я с ним лучшие результаты.

check45=RK45(fun_integrator, 0, y0, max(t), max_step=1800, \
             rtol=1e-11, atol=1e-12)
for i in range(len(t)):
    dt=0+0.3*i*86400
    check45.step() #step has no input
    x_E45=check45.y
    print(x_E45[0:3])  

НО как ввести размер шага в приведенном выше коде?

Для получения дополнительной информации: Функция и y0:

def fun_integrator(t,y):
    G=6.67428*10**(-11)/(10**3)**3 #Km**3/(Kg s**2) 
    m_E=5.97218639014246e+24 #Kg
    m_M=7.34581141668673e+22 #Kg
    m_S=1.98841586057223e+30 #Kg
#    c=2.997924580000000e+05 # [Km/s], speed of light, IERS TN36 p. 18
    x_E=y[0:3]
    x_M=y[6:9]
    x_S=y[12:15]
    ##
#    v_E=y[0,3:6]
#    v_M=y[0,9:12]
#    v_S=y[0,15:18]
    ##
    diff_EM=x_E-x_M
    diff_SM=x_S-x_M
    diff_ES=x_E-x_S
    d_EM=math.sqrt(diff_EM[0]**2 + diff_EM[1]**2 + diff_EM[2]**2)
    d_SM=math.sqrt(diff_SM[0]**2 + diff_SM[1]**2 + diff_SM[2]**2)
    d_ES=math.sqrt(diff_ES[0]**2 + diff_ES[1]**2 + diff_ES[2]**2)
    ##
    dydt= y[3:6] #E vel
    two=G*((m_M*(-diff_EM)/d_EM**3) + (m_S*(-diff_ES)/d_ES**3)) # E acc
    three=y[9:12] #M vel
    four=G*((m_S*(diff_SM)/d_SM**3) + (m_E*(diff_EM)/d_EM**3)) # M acc
    five=y[15:18] #S vel
    six=G*((m_E*(diff_ES)/d_ES**3) + (m_M*(-diff_SM)/d_SM**3)) # S acc
    dydt=np.append(dydt,two)
    dydt=np.append(dydt,three)
    dydt=np.append(dydt,four)
    dydt=np.append(dydt,five)
    dydt=np.append(dydt,six)
    return dydt

y0=np.array([0.18030617557041088626562258966E+08, #Epos
-0.13849983879561028969707483658E+09,
-0.60067586558743159549398380427E+08,
0.29095339700433727181771510027E+02, #Evel
0.30306447236947439878791802685E+01,
0.13145956648460951506322034682E+01,
0.17909715946785370737211415301E+08, #Mpos
-0.13879823119464902933064808964E+09,
-0.60230238740754862546525906740E+08,
0.30136092114725188798503502634E+02, #Mvel
0.27407201232607066962011074680E+01,
0.11664485102480685879418310910E+01,
0.67356572699027185845872823900E+06, #Spos
0.11475300015697844979868843500E+06,
0.39801697980815553718511148000E+05,
-0.60903913908114150920444000000E-03, #Svel
0.89648366457310610847232000000E-02,
0.38595942076153950302606500000E-02])

person Vishu Singh    schedule 20.06.2019    source источник
comment
Откуда вы знаете, что результаты Matlab (неявный многошаговый с адаптивным порядком 1-13) лучше? Как вы думаете, почему явное повторение того, что solve_ivp делает внутри класса RK45, даст существенно разные результаты? Вы пытались использовать другие классы решателя, такие как LSODA или RADAU в solve_ivp?   -  person Lutz Lehmann    schedule 20.06.2019
comment
Да, я пробовал LSODA и другие варианты в solve_ivp, все они дают более или менее похожие результаты. Я знаю, что результаты MATLAB (как с ode45, так и с ode113, с размером шага 1800) лучше, потому что у меня есть значения для сравнения для разных эпох. Я предполагаю, что один из интеграторов (RK45, RK23 и т. д.) мог бы дать такие же хорошие результаты, как MATLAB, или даже лучше. Поскольку MATLAB использует для вычислений 16 цифр, а мои результаты должны быть очень точными, я надеюсь реализовать все на python, чтобы в конце получить лучшую точность.   -  person Vishu Singh    schedule 21.06.2019
comment
Возможно, вы захотите изменить t = np.linspace(0,0+0.3*(pts-1)*86400,20) на t = np.linspace(0,0+0.3*(pts-1)*86400,pts) для согласованности при изменении pts со значения 20.   -  person Lutz Lehmann    schedule 21.06.2019
comment
Хотя solve_ivp и стоящие за ним классы — это чистый python, если я правильно помню то, что когда-то читал, я не уверен, что он будет безупречно работать с типами данных с множественной точностью. Возможно, вам придется использовать для этого свою собственную реализацию, если я правильно понимаю вашу цель более высокой точности.   -  person Lutz Lehmann    schedule 21.06.2019


Ответы (1)


Чтобы ответить на фактический вопрос, а не на основной вопрос:

Вы можете использовать метод плотности_вывода для вычисления значения в конкретный желаемый момент времени. В противном случае вы сильно потеряете в точности своего решения, если, например, попытаетесь использовать свой собственный метод интерполяции.

Но я хотел бы отметить, чтоsolve_ivp (с использованием метода RK45), по сути, является простой в использовании оболочкой для этого кода, поэтому я не ожидаю ничего существенного в этом случае.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.RK45.dense_output.html#scipy.integrate.RK45.dense_output

person Matthew Flamm    schedule 05.09.2019