Есть ли идиоматический способ завершить интеграцию после n обратных вызовов в DifferentialEquations.jl

#julia #differential-equations

#джулия #дифференциальные уравнения

Вопрос:

Прежде всего, я использую DifferentialEquations.jl библиотеку, которая является фантастической! В любом случае, мой вопрос заключается в следующем:

Скажем, например, у меня есть следующее дифференциальное уравнение:

 function f(du, u, t)
    du[1] = u[3]
    du[2] = u[4]
    du[3] = -u[1] - 2 * u[1] * u[2]
    du[4] = -u[2] - u[1]^2   u[2]^2
end
  

и у меня есть обратный вызов, который запускается каждый раз, когда траектория пересекает ось y:

 function condition(u, t, integrator)
    u[2]
end
  

Однако мне нужно, чтобы интеграция завершилась ровно после 3 пересечений. Я знаю, что интеграция может быть прекращена с помощью эффекта:

 function affect!(integrator)
    terminate!(integrator)
end
  

но каков правильный способ разрешить подсчет количества обратных вызовов до тех пор, пока не будет выполнен критерий завершения. Кроме того, есть ли способ распространить эту методологию на n событий с n разными подсчетами?

В моих исследованиях мне часто приходится просматривать карты Пуанкаре и первое, второе, третье и т. Д. Возвращаются к карте, Поэтому мне нужна структура, которая позволяет мне выполнять это завершение подсчета. Я все еще новичок в Julia и поэтому пытаюсь на ранней стадии усилить хороший идиоматический код. Любая помощь приветствуется и, пожалуйста, не стесняйтесь обращаться за разъяснениями.

Ответ №1:

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

Если вы перейдете userdata = Dict(:my_key=>:my_value) к solve , то вы можете получить доступ к этому из integrator.opts.userdata[:my_key] .

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

 function f(du, u, t)
    du[1] = sin(t)
end
function condition(u, t, integrator)
    u[1] 
end

function affect!(integrator)
    integrator.opts.userdata[:callback_count]  =1
    if integrator.opts.userdata[:callback_count] == integrator.opts.userdata[:max_count]
        terminate!(integrator)
    end
end


callback = ContinuousCallback(condition, affect!)

u0 = [-1.]
tspan = (0., 100.)

prob = ODEProblem(f, u0, tspan)
sol = solve(prob; callback=callback, userdata=Dict(:callback_count=>0, :max_count=>3))
  

Комментарии:

1. Отлично, спасибо! Просто на заметку, чтобы это работало на моей машине, мне пришлось добавить ввод параметра в f , т. Е. Изменить Определение функции на f(du, u, p, t) . Но в остальном это отлично решает мою проблему, очень ценится.