{"action":"created","issue":{"url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/11","repository_url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl","labels_url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/11/labels{/name}","comments_url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/11/comments","events_url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/11/events","html_url":"https://github.com/JuliaDiffEq/ODE.jl/issues/11","id":26766377,"number":11,"title":"Event functions","user":{"login":"tlycken","id":1550920,"avatar_url":"https://avatars.githubusercontent.com/u/1550920?v=3","gravatar_id":"","url":"https://api.github.com/users/tlycken","html_url":"https://github.com/tlycken","followers_url":"https://api.github.com/users/tlycken/followers","following_url":"https://api.github.com/users/tlycken/following{/other_user}","gists_url":"https://api.github.com/users/tlycken/gists{/gist_id}","starred_url":"https://api.github.com/users/tlycken/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tlycken/subscriptions","organizations_url":"https://api.github.com/users/tlycken/orgs","repos_url":"https://api.github.com/users/tlycken/repos","events_url":"https://api.github.com/users/tlycken/events{/privacy}","received_events_url":"https://api.github.com/users/tlycken/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":13,"created_at":"2014-02-02T18:31:08Z","updated_at":"2016-10-16T04:36:25Z","closed_at":null,"body":"For some problems, it is interesting to run the solver until something happens - specified by (part of) the solution at that point. In those cases, it can be hard to know on beforehand exactly when this happens, so it's difficult to give an upper limit to the solution domain.\r\n\r\nFor example, think about a program modelling a bouncing ball: it's just solving F = ma for a free-falling object, except every time the ball hits the floor, we want to change sign of the y-component of its velocity. Without event functions, one has to solve for one parabola at a time, obtain the final components of the velocity, change the sign and use as initial values for the next - with them, one can let the solver do the work.\r\n\r\nIt could also be nice to be able to stop the simulation when some condition is met, rather than after a final time - for a system that you expect to stabilize but you don't know how long it's going to take, you can then stop when the rate of change in the solution is small enough.\r\n\r\nBasically, the solvers should support some way of saying `every time X happens, do Y` where `Y` can be anything from changing some part of the problem to stopping the solver. As noted in #7 it could also be interesting to support only emitting solution points when some condition is met, which could also be specified by an event function.\r\n\r\nWhat is a good way of implementing this in the current solvers? What should the user interface look like?"},"comment":{"url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/comments/254027070","html_url":"https://github.com/JuliaDiffEq/ODE.jl/issues/11#issuecomment-254027070","issue_url":"https://api.github.com/repos/JuliaDiffEq/ODE.jl/issues/11","id":254027070,"user":{"login":"ChrisRackauckas","id":1814174,"avatar_url":"https://avatars.githubusercontent.com/u/1814174?v=3","gravatar_id":"","url":"https://api.github.com/users/ChrisRackauckas","html_url":"https://github.com/ChrisRackauckas","followers_url":"https://api.github.com/users/ChrisRackauckas/followers","following_url":"https://api.github.com/users/ChrisRackauckas/following{/other_user}","gists_url":"https://api.github.com/users/ChrisRackauckas/gists{/gist_id}","starred_url":"https://api.github.com/users/ChrisRackauckas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ChrisRackauckas/subscriptions","organizations_url":"https://api.github.com/users/ChrisRackauckas/orgs","repos_url":"https://api.github.com/users/ChrisRackauckas/repos","events_url":"https://api.github.com/users/ChrisRackauckas/events{/privacy}","received_events_url":"https://api.github.com/users/ChrisRackauckas/received_events","type":"User","site_admin":false},"created_at":"2016-10-16T04:36:24Z","updated_at":"2016-10-16T04:36:24Z","body":"Thank you for this thread. I used a lot of ideas from here. I just finished implementing callbacks in [DifferentialEquations.jl](http://juliadiffeq.github.io/DifferentialEquations.jl/latest/man/callback_functions.html) and made sure the easy interface addressed at least all of the concerns here (it does a lot more, but at least everything here). For example, the easy interface signature is (in full, only `event_f` and `apply_event!` don't have defaults)\r\n\r\n```julia\r\ncallback = @ode_callback begin\r\n  @ode_event event_f apply_event! rootfind_event_loc interp_points terminate_on_event Δt_safety\r\nend\r\n```\r\n\r\n1. The option `terminate_on_event` doesn't use exceptions because those have many complications (including causing performance issues if you're solving a lot of ODEs). Instead it makes the final timepoint equal to the current timepoint, so the loop will simply end itself and undergo any postamble\r\n\r\n2. This form of termination allows one to solve on a timespan `[0;Inf]` for cases where the end is not known.\r\n\r\n3. This callback is only called when the step is accepted, addressing @acroy's concern. \r\n\r\n4. This type of event has `Δt_safety` which will be a multiplier to Δt which can be used to do things like @ivarne was talking about. But using the event to directly go to the time of the event is already automatic if `rootfind_event_loc` is true (it will rootfind to the event), so that would actually handle @ivarne 's case better.\r\n\r\n5. [A lot of the DifferentialEquations.jl algorithms have higher than 3rd order interpolations, up to 9th order](http://juliadiffeq.github.io/DifferentialEquations.jl/latest/solvers/ode_solve.html) which are used for the rootfinding and event detection. This is why a DSL with macros was created because there's a lot of \"algorithm specific code\".\r\n\r\n6. This implementation is pretty well optimized, and since [the DifferentialEquations.jl algorithms benchmark at around 10x faster than the ODE.jl algorithms](https://github.com/JuliaDiffEq/DifferentialEquations.jl/blob/master/benchmarks/Linear%20Work-Precision%20Diagrams.ipynb), this should address your performance concerns @spencerlyon2. I say \"pretty well\" since there is one place where there's allocations, but it has a pretty trivial fix: JuliaDiffEq/DifferentialEquations.jl#66. Then the implementation will be allocation-free and very swift. On all of the problems I've checked the callbacks inline as well.\r\n\r\n7. I didn't add the progress callback as @acroy mentions since [I already do that somewhere else](http://juliadiffeq.github.io/DifferentialEquations.jl/latest/man/progress_bar.html). I could move that in here, but it just seems unnecessary. Someone could add their own progressbar in the callback function though.\r\n\r\n8. One other cool feature I'd like to mention is that you can change the size of the ODE along the way by using this. I think it's cool.\r\n\r\nOnce again, thank you for this thread of ideas. It was a helpful source of \"user-concerns\" throughout the design/implementation. "}}
{"actor":{"display_login":"ChrisRackauckas"}}