#python #scipy
#python #scipy
Вопрос:
Scipy уходит от odeint
towards solve_ivp
, который больше не поддерживает передачу дополнительных аргументов для функции dynamics. Вместо этого рекомендуется использовать лямбды. Однако, когда я пытаюсь сделать то же самое для событий, они не работают должным образом. Есть мысли?
MWE (изменено со страницы документа):
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
# dynamics of a simple mass with ballistic flight and a bit of drag
def cannon(t, y, p):
return [y[2],y[3], -p['friction']*y[2], p['gravity']-p['friction']*y[3]]
# termination condition: cannonball hits the ground
# this event does not require parameters, but more complex events might
def hit_ground1(t, y, p):
return y[1]
hit_ground1.terminal = True
hit_ground1.direction = -1
def hit_ground2(t,y):
return y[1]
hit_ground2.terminal = True
hit_ground2.direction = -1
p = {'gravity':-1,'friction':0} # paramters as a dict
y0 = [0, 0, 0, 10] # initial conditions
t_span = [0, 22] # integration time a bit over what is necessary
# we can handle dynamics with parameters by using lambdas
# but somehow the same doesn't seem to work with events
sol1 = solve_ivp(fun=lambda t,x:cannon(t,x,p), t_span=t_span,
y0=y0, events=hit_ground2, max_step=0.01)
sol2 = solve_ivp(fun=lambda t,x:cannon(t,x,p), t_span=t_span,
y0=y0, events=lambda t,x:hit_ground1(t,x,p), max_step=0.01)
print(sol1.t[-1]) # terminates correctly
print(sol2.t[-1]) # continues integrating
plt.plot(sol1.t,sol1.y[1], linewidth=3)
plt.plot(sol2.t,sol2.y[1],'--',linewidth=3)
plt.show()
Комментарии:
1. Вскоре после вашего вопроса они
args
были добавлены снова , по крайней мере, для функции RHS. Не удается найти что-либо дляevent
функции… Что-то, что мне нужно для моего использования. Может быть, я попробую этотlambda
подход.
Ответ №1:
Свойства события, terminal
и direction
, не передаются в ваше лямбда-выражение. Вам нужно сохранить свой лямбда-код в переменную и добавить свойства туда, а не в hit_ground1
функцию.
def hit_ground1(t, y, p):
return y[1]
ground_event = lambda t,x:hit_ground1(t,x,p)
ground_event.terminal = True
ground_event.direction = -1
Используйте это событие, и оно должно работать так, как ожидалось.
sol2 = solve_ivp(fun=lambda t,x:cannon(t,x,p), t_span=t_span,
y0=y0, events=ground_event, max_step=0.01)
Комментарии:
1. Стив, запустив print (sol1.t_events); print(sol2.t_events) решатель перехватил события, t = 20. появилось в обоих методах. Не знаю, почему sol2, hitground1 также поймали t = 0.. Этого не происходит в решении Алекса