Output from DifferentialEquations.jl at specific points - julia

I've trying to use DifferentialEquations.jl from Julia. I managed to get it working but I'd like know how to generate output at specific time points. The docs aren't clear on this and I've not found a single example that does this. The code I'm currently using is from the tutorial:
using DifferentialEquations
using Plots
function lorenz(du,u,p,t)
du[1] = 10.0*(u[2]-u[1])
du[2] = u[1]*(28.0-u[3]) - u[2]
du[3] = u[1]*u[2] - (8/3)*u[3]
end
u0 = [1.0;0.0;0.0]
tspan = (0.0,100.0)
prob = ODEProblem(lorenz,u0,tspan)
sol = solve(prob)
plot(sol,vars=(1,2,3))
Currently it generates 1287 points, and I've no idea how it decides that. My question is what if I wanted to generate 20 points between the span 0 to 100?

The ODE tutorial section on "Controlling the Solvers" demonstrates using saveat for this purpose. The demonstration is:
sol = solve(prob,reltol=1e-6,saveat=0.1)
which will save at 0.0, 0.1, ... in your example. Right below that it is noted that:
More generally, saveat can be any collection of time points to save at.
So for example, we can use save at to save only at t=30, 60, and 78 as follows:
sol = solve(prob,saveat=[30.0,60.0,78.0])
These examples should put you in the right direction. For more details, see the Output Controls section of the documentation.

Related

Julia's DifferentialEquations issue in converting solution to array

I solved a system of differential equations (van der Pol equations) using DifferentialEquations.
I would like to export the solution. To do this I used convert(Array,sol), however, the converted solution is not the same as the solution I get by sol.
See the code below for more explanation:
using DifferentialEquations
using Plots
function fun(du,u,p,t)
du[1] = u[2]
du[2] = 1000*(1-u[1]^2)*u[2]-u[1]
end
u0 = [2.0,0.0]
tspan = (0.0,3000.0)
prob = ODEProblem(fun,u0,tspan)
sol = solve(prob)
a = convert(Array,sol)#Here I tried to convert the solution to an array
plot(a[1,:])
plot(sol,vars = 1)
a = convert(Array,sol)
plot(a[1,:]) returns:
plot(sol,vars = 1) returns:
The converted solution is the same as what is contained in sol. The problem lies in the fact that the step size for the variable in the x axis (here it is time) is not uniform. So only plotting using plot(a[1,:]) is not enough. We must provide at what time the solution has the value it has. Using plot(sol.t,a[1,:]) plot the right answer.

How do I write a piecewise Differential Equation in Julia?

I am new to Julia, I would like to solve this system:
where k1 and k2 are constant parameters. However, I=0 when y,0 or Ky otherwise, where k is a constant value.
I followed the tutorial about ODE. The question is, how to solve this piecewise differential equation in DifferentialEquations.jl?
Answered on the OP's cross post on Julia Discourse; copied here for completeness.
Here is a (mildly) interesting example $x''+x'+x=\pm p_1$ where the sign of $p_1$ changes when a switching manifold is encountered at $x=p_2$. To make things more interesting, consider hysteresis in the switching manifold such that $p_2\mapsto -p_2$ whenever the switching manifold is crossed.
The code is relatively straightforward; the StaticArrays/SVector/MVector can be ignored, they are only for speed.
using OrdinaryDiffEq
using StaticArrays
f(x, p, t) = SVector(x[2], -x[2]-x[1]+p[1]) # x'' + x' + x = ±p₁
h(u, t, integrator) = u[1]-integrator.p[2] # switching surface x = ±p₂;
g(integrator) = (integrator.p .= -integrator.p) # impact map (p₁, p₂) = -(p₁, p₂)
prob = ODEProblem(f, # RHS
SVector(0.0, 1.0), # initial value
(0.0, 100.0), # time interval
MVector(1.0, 1.0)) # parameters
cb = ContinuousCallback(h, g)
sol = solve(prob, Vern6(), callback=cb, dtmax=0.1)
Then plot sol[2,:] against sol[1,:] to see the phase plane - a nice non-smooth limit cycle in this case.
Note that if you try to use interpolation of the resulting solution (i.e., sol(t)) you need to be very careful around the points that have a discontinuous derivative as the interpolant goes a little awry. That's why I've used dtmax=0.1 to get a smoother solution output in this case. (I'm probably not using the most appropriate integrator either but it's the one that I was using in a previous piece of code that I copied-and-pasted.)

Trouble with DifferentialEquations.jl

I'm quite new to Julia and I'm currently learning how to solve differential equations with it. I tried to run a simple pre-made code by Christopher Rackauckas, but I got an error. The code can be found here. I will also write it here:
using DifferentialEquations
alpha = 0.5 #Setting alpha to 1/2
f(y,t) = alpha*y
u0 = 1.5
prob = ODEProblem(f,u0)
timespan = [0,1] # Solve from time = 0 to time = 1
sol = solve(prob,timespan) # Solves the ODE
using Plots
plot(sol) # Plots the solution using Plots.jl
And the error I'm getting looks like this:
LoadError: MethodError: no methof matching DiffEqBase.ODEProblem{uType,tType,isinplace,FC;MM}(::#f, ::Float64)
I also tried to run other similar codes and even removed the DifferentialEquations.jl -package and then reinstalled it, but nothing changed.
Anyone more experienced having an idea what I might be doing wrong?
The issue is that blog post is from quite a long time ago. Or at least, DifferentialEquations 1.0 had a few breaking changes in this part. You should use the tutorial instead, which fixes this example to the newest version. The solution is:
using DifferentialEquations
alpha = 0.5 #Setting alpha to 1/2
f(y,t) = alpha*y
u0 = 1.5
tspan = (0.0,1.0) # Solve from time = 0 to time = 1
prob = ODEProblem(f,u0,tspan)
sol = solve(prob) # Solves the ODE
using Plots
plot(sol) # Plots the solution using Plots.jl
But now that I know people are still looking at that old post, I updated its syntax to be correct.

Animating the solution to an ODE in Julia

I have a julia code:
using DifferentialEquations
using Plots
using ParameterizedFunctions
plotly()
lorenz = #ode_def Lorenz begin
dx = σ*(y-x)
dy = ρ*x-y-x*z
dz = x*y-β*z
end σ = 10. β = 8./3. ρ => 28.
u0 = [1., 5., 10.]
tspan = (0., 2.)
prob = ODEProblem(lorenz, u0, tspan)
sol = solve(prob,save_timeseries=true)
plot(sol,vars=(:x,:y,:z))
Which results in:
next plot
How can i animate this plot such that it would work either from REPL and jupyter?
For DifferentialEquations.jl, there is a built-in animation function which can handle this. Unfortunately, I realized that I forgot to put it in the last release. When it's released, the syntax will be (simplifying your code a little bit):
using DifferentialEquations
using Plots
using ParameterizedFunctions
pyplot()
lorenz = #ode_def Lorenz begin
dx = σ*(y-x)
dy = ρ*x-y-x*z
dz = x*y-β*z
end σ = 10. β = 8./3. ρ => 28.
u0 = [1., 5., 10.]
tspan = (0., 2.)
prob = ODEProblem(lorenz, u0, tspan)
sol = solve(prob)
animate(sol,vars=(:x,:y,:z),xlims=(-20,20),ylims=(-15,20),zlims=(10,40))
A few things: animate can take any of the normal plot commands. However, it at each frame it plots from the beginning to the ith step, which means you may need to manually set the axis to make them not shift around. Another thing to note is that I switched backends to PyPlot. The Plotly backend cannot do animations. Maybe PlotlyJS can? The animation function is documented here.
Using that command will be by far the easiest way, but you can do it "more manually" using the integrator interface. Essentially, you can just plot each step interval using this and get to the same place in the end. You'd have to use Plots.jl's animation interface.
Edit: If you Pkg.update() this should now work.

Simulate a bouncing ball?

Is it possible to create a simple model of a bouncing ball, using Julia's equation solvers?
I started with this:
using ODE
function bb(t, f)
(y, v) = f
dy_dt = v
dv_dt = -9.81
[dy_dt, dv_dt]
end
const y0 = 50.0 # height
const v0 = 0.0 # velocity
const startpos = [y0; v0]
ts = 0.0:0.25:10 # time span
t, res = ode45(bb, startpos, ts)
which produces useful-looking numbers:
julia> t
44-element Array{Float64,1}:
0.0
0.0551392
0.25
0.5
0.75
1.0
⋮
8.75
9.0
9.25
9.5
9.75
10.0
julia> res
44-element Array{Array{Float64,1},1}:
[50.0,0.0]
[49.9851,-0.540915]
[49.6934,-2.4525]
[48.7738,-4.905]
[47.2409,-7.3575]
⋮
[-392.676,-93.195]
[-416.282,-95.6475]
[-440.5,-98.1]
But somehow it needs to intervene when the height is 0, and reverse the velocity. Or am I on the wrong track?
DifferentialEquations.jl offers sophisticated callbacks and event handling. Since the DifferentialEquations.jl algorithms are about 10x faster while offering a higher order interpolation, these algorithms are clearly the better choose here anyways.
The first link is the documentation which shows how to do the event handling. The easy interface uses the macros. I start by defining the function.
f = #ode_def BallBounce begin
dy = v
dv = -g
end g=9.81
Here I am showing ParameterizedFunctions.jl to make the syntax nicer, but you can define the function directly as an in-place update f(t,u,du) (like Sundials.jl). Next you define the function which determines when an event takes place. It can be any function which is positive and hits zero at the event time. Here, we are checking for when the ball hits the ground, or for when y=0, so:
function event_f(t,u) # Event when event_f(t,u,k) == 0
u[1]
end
Next you say what to do when the event occurs. Here we want to reverse the sign of the velocity:
function apply_event!(u,cache)
u[2] = -u[2]
end
You put these functions together to build the callback using the macros:
callback = #ode_callback begin
#ode_event event_f apply_event!
end
Now you solve as usual. You define the ODEProblem using f and the initial condition, and you call solve on a timespan. The only thing extra is you pass the callback along with the solver:
u0 = [50.0,0.0]
prob = ODEProblem(f,u0)
tspan = [0;15]
sol = solve(prob,tspan,callback=callback)
Then we can use the plot recipe to automatically plot the solution:
plot(sol)
The result is this:
A few things to notice here:
DifferentialEquations.jl will automatically use an interpolation to more safely check for the event. For example, if the event happened within a timestep but not at the ends, DifferentialEquations.jl will still find it. More or less interpolations points can be included as options to the #ode_event macro.
DifferentialEquations.jl used a rootfinding method to hone in on the moment of the event. Even though the adaptive solver steps past the event, by using rootfinding on the interpolation it finds the exact time of the event, and thus gets the discontinuity right. You can see that in the graph since the ball never goes negative.
There is a whole lot more this can do. Check out the docs. You can do pretty much anything with this. For example, have your ODE changing size over the run to model a population of cells with birth and deaths. This is something other solver packages can't do.
Even with all of these features, speed is not compromised.
Let me know if you need any extra functionality added to the "ease of use" interface macros.
Somewhat hacky:
function bb(t, f)
(y, v) = f
dy_dt = v
dv_dt = -9.81*sign(y)
[dy_dt, dv_dt]
end
where you just follow a convention where y and -y refer to the same heights. You can then plot the trajectory of the bouncing ball by just plotting abs(y).

Resources