# Use a time-series as parameter of ODEProblem

**URL:** <https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945>\
**Category:** New to Julia\
**Tags:** ordinarydiffeq\
**Created:** [June 17, 2022, 10:15pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945 "2022-06-17T22:15:51Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 17, 2022, 10:15pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/1 "2022-06-17T22:15:51Z")

</div>

Hello,

I am quite new to Julia and I would like to use it to solve some ODE problems.  
Let’s take the following example:

```julia
function test!(du,u,p,t)
    yield = 10
    decay = 5
    du[1] = yield*p - decay*u[1]
end

```

I can then define some variables and run the solver:

```julia
u0 = [0]
tspan = (0,10)
p = 3

prob = ODEProblem(test!,u0,tspan,p)
sol = solve(prob);

```

That’s fine.  
But I then would like to use a time-series for p (p is a time-varying variable which is recorded in some file). For example let’s take:

```julia
ts_time = (0:11)
ts_val = [1, 1, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0]

```

I saw in the examples of [DifferentialEquations.jl](https://diffeq.sciml.ai/stable/tutorials/ode_example/#Example-2:-Solving-Systems-of-Equations) that one casn define a time dependent function to send to the ODEProblem.  
So I tried by linear interpolation:

```julia
ts = LinearInterpolation(ts_time, ts_val)

```

Now I can use `ts` as a time dependent function. I tried to sent it to the solver:

```julia
prob = ODEProblem(test!,u0,tspan,ts)
sol = solve(prob);

```

But it results to some error:

```julia
BoundsError: attempt to access 12-element extrapolate(scale(interpolate(::Vector{Float64}, BSpline(Linear())), (0:11,)), Throw()) with element type Float64 at index [12]

```

I do not understand what’s the problem here.

I also tried a formulation more similar to the example:

```julia
ts2 = t->ts(t)
prob = ODEProblem(test!,u0,tspan,ts2)
sol = solve(prob);

```

In this case I get the following error:

```julia
MethodError: no method matching *(::Int64, ::var"#25#26")
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
  *(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:88
  *(::Union{Int16, Int32, Int64, Int8}, ::BigInt) at gmp.jl:541

```

I can I do what I am trying to do (potentially with a different approach…)?  
Thanks in advance

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 18, 2022, 3:43am UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/2 "2022-06-18T03:43:29Z")

</div>

Since it’s an interpolation, you have to use the interpolation.

```julia
function test!(du,u,p,t)
    yield = 10
    decay = 5
    du[1] = yield*p(t) - decay*u[1]
end

```

`p` is just whatever you passed it. So when you did:

```julia
prob = ODEProblem(test!,u0,tspan,ts)
sol = solve(prob);

```

`p` is the `LinearInterpolation` object. So then `yield*p` tried to do multiplication between a scalar and a `LinearInterpolation`, which is what then causes the error message you see. But `yield*p(t)`, well, that first interpolates `p` to get a scalar, then use that scalar, and it etc. does what you want.

From that description you can see how the other error you get is similar, with a similar solution to call the function.

---

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 19, 2022, 9:13pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/3 "2022-06-19T21:13:21Z")

</div>

Thanks for your help…now it looks so obvious 😇

I am wondering whether the _interpolation technique_ is a little bit too excessive. Maybe the best (fastest) approach would be to impose the time-step so that `t` always corresponds to one of the points of my table. So that no interpolation is necessary.  
In my case, the phenomena is “slow enough” compared to the input time-series frequency so that no further time-step refinement would be necessary.

But can I impose to the solver the list of time points? Than I could maybe define p as a Dict so that the right p-value would corresponds to each time.  
Again, I do not know if this is the best approach…

I tried to develop a similar approach via a for loop, where at each iteration I define and solve an ODEProblem dealing with a single time-step. But I suppose that doing that with a for loop is not the fastest way…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 19, 2022, 10:06pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/4 "2022-06-19T22:06:02Z")

</div>

> [@Songio](#):
>
> But I suppose that doing that with a for loop is not the fastest way…

Well, for loops in Julia are fast. Nothing wrong with using a for loop…

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 19, 2022, 10:50pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/5 "2022-06-19T22:50:40Z")

</div>

> [@Songio](#):
>
> I tried to develop a similar approach via a for loop, where at each iteration I define and solve an ODEProblem dealing with a single time-step. But I suppose that doing that with a for loop is not the fastest way…

Depends on how nonlinear your equation is.

> [@Songio](#):
>
> But can I impose to the solver the list of time points? Than I could maybe define p as a Dict so that the right p-value would corresponds to each time.

You can pass `tstops` as an array of time points for the solver to hit, and then have a `DiscreteCallback` that updates a parameter value at those points and just use the constant value between them. You could also set `adaptive=false` and then those would be exactly the time steps, though whether that is okay depends on the required accuracy of the solution.

---

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 20, 2022, 9:15pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/6 "2022-06-20T21:15:08Z")

</div>

I think I am doing something weird here: I tried to implement the same `for loop` in python (with odeint) and Julia and I get more or less the same execution time…(0.5 seconds for about 2300 time steps) Julia is even a little bit slower and I am surprised…

However, with the linear interpolation approach the execution time is now reduced to about 0.03 seconds, so a reduction greater than 10x!

But to make things a little bit more confused, I tried to implement the linear interpolation approach also in python with `scipy.interpolate.interp1d`: in this case, I get by far the worst execution times (even compared to the for loops).

I should probably try to identify the bottleneck of each configuration…

Finally, not knowing how `DiscreteCallback` works, I tried to set `adaptive=false`…but I got some kind of errors saying that the time-step does not correspond to any index of my p (which is now a Dict)…I tried to `round` but with no success…I do not know if this pathway is worth the effort…

In any case thanks to everybody for your support and for making me process in Julia. 🙂

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 20, 2022, 10:08pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/7 "2022-06-20T22:08:52Z")

</div>

> [@Songio](#):
>
> I think I am doing something weird here: I tried to implement the same `for loop` in python (with odeint) and Julia and I get more or less the same execution time…(0.5 seconds for about 2300 time steps) Julia is even a little bit slower and I am surprised…

Was it in global scope?

---

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 21, 2022, 8:44am UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/8 "2022-06-21T08:44:08Z")

</div>

Not sure to understand what should be in global scope and what that would change. So, let me write down what I tested 🙂:

```julia
# Define the variable "p" and its interpolation
ts_time = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 100.] #Array(0.:11.)
ts_val = [1., 1., 3., 3., 3., 0., 0., 0., 0., 0., 0., 0.]
ts = LinearInterpolation(ts_time, ts_val);

# The function with "p(t)"
function test_t!(du,u,p,t)
    yield = 10
    decay = 5
    du[1] = yield*p(t) - decay*u[1]
end

#And then a test
for i in 1:5
    start = time()
    prob = ODEProblem(test_t!,u0,tspan,ts)
    global sol_t = solve(prob,saveat=1.);
    println(time()-start)
end

```

Which results in:

```julia
2.2445149421691895
0.0003249645233154297
0.00017905235290527344
0.00015592575073242188
0.0001480579376220703

```

Let’s test the `for-loop` approach:

```julia
# Function to run the transient as a `for-loop`
function test_transient(time_steps,p,u0)
    
    n_of_steps = length(time_steps)
    u = u0 * ones(n_of_steps)

    for i in range(2,stop=n_of_steps)
        tspan = (time_steps[i-1],time_steps[i])
        pi = p[i]
        u0 = [u[i-1]]
        
        prob = ODEProblem(test!,u0,tspan,pi)
        local sol = solve(prob,save_everystep=false)      
        u[i] = sol.u[end][1]       
    end

    return u
end

# Testing it
for i in 1:5
    start = time()
    global sol = test_transient(ts_time[1:end-1],ts,0)
    println(time()-start)
end

```

Which leads to:

```julia
4.448390007019043
0.0010211467742919922
0.0009670257568359375
0.0009632110595703125
0.0009682178497314453

```

So 5-10x slower  
Surprisingly (at least for me), the results are not really identical. There is some “shift” in the ‘p’ parameter that I have to correct…but I do not think that this affect the speed test…  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/0/c/0c69ae1ada3eab4fcd5bf8c6d800cb91bb7e2205.png)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 21, 2022, 9:03am UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/9 "2022-06-21T09:03:20Z")

</div>

Reconstructing a new ODE problem and new solve in a loop is going to be really slow because it’s building and releasing the cache every step. If you want to do that, then using the integrator interface is better:

[https://diffeq.sciml.ai/stable/basics/integrator/](https://diffeq.sciml.ai/stable/basics/integrator/)

And yes, make sure the definition is matching left vs right value choices.

---

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 21, 2022, 8:50pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/10 "2022-06-21T20:50:51Z")

</div>

Thanks for the suggestion: the integrator interface looks great for what I want to do.

However, I am getting errors since the very start of my code using it…probably due to my inexperience with Julia. I use the `init` function as `solve`, as I understood from instructions. However, I am getting a “typical Julia” error message:

```julia
MethodError: no method matching __init(::ODEProblem{Float64, Tuple{Float64, Float64}, true, Float64, ODEFunction{true, typeof(test!), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem})

```

Here follows my test:

```julia
function test_integrate(time_steps,p,u0)

    n_of_steps = length(time_steps)
    
    u = u0 * ones(n_of_steps)

    println("define prob")
    prob = ODEProblem(test!,u0,(time_steps[1],time_steps[end]),p[1])
    println("init integrator")
    integrator = init(prob)
 
    for i in range(2,stop=n_of_steps)
        println("step",str(i))
        integrator.p = power[i]
        step!(integrator,time_steps[i-1]-time_steps[i],stop_at_tdt=true)        
    end
    
    return integrator
end

sol = test_integrate(ts_time[1:end-1],ts,0)

```

Thanks in advance for helping me with my newbie-issues…

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 21, 2022, 8:54pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/11 "2022-06-21T20:54:49Z")

</div>

> [@Songio](#):
>
> However, I am getting errors since the very start of my code using it…probably due to my inexperience with Julia. I use the `init` function as `solve`, as I understood from instructions. However, I am getting a “typical Julia” error message:

Similar to `solve`, you should pass an algorithm if you’re directly using a solver package instead of DifferentialEquations.jl.

Open an issue and I can have it catch this one. The typical one is `solve` which looks like this:

```julia
julia> using OrdinaryDiffEq

julia> prob = ODEProblem((u,p,t)->1.0,1.0,(0.0,1.0))
ODEProblem with uType Float64 and tType Float64. In-place: false
timespan: (0.0, 1.0)
u0: 1.0

julia> solve(prob)
ERROR: Default algorithm choices require DifferentialEquations.jl.
Please specify an algorithm (e.g., `solve(prob, Tsit5())` for an ODE)
or import DifferentialEquations directly.

You can find the list of available solvers at https://diffeq.sciml.ai/stable/solvers/ode_solve/
and its associated pages.

Stacktrace:
  [1] __solve(prob::ODEProblem{Float64, Tuple{Float64, Float64}, false, SciMLBase.NullParameters, ODEFunction{false, var"#7#8", LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, args::Nothing; default_set::Bool, second_time::Bool, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})

```

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 21, 2022, 8:59pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/12 "2022-06-21T20:59:34Z")

</div>

Nevermind, no need for the issue, the better error message was quick to add for the init case: [Handle no defaults on init case by ChrisRackauckas · Pull Request #780 · SciML/DiffEqBase.jl · GitHub](https://github.com/SciML/DiffEqBase.jl/pull/780) thanks for the report.

---

<div class="post-metadata">

**Author:** ![Songio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/songio/32/37261_2.png) [@Songio](https://discourse.julialang.org/u/Songio)\
**Post date:** [June 21, 2022, 10:18pm UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/13 "2022-06-21T22:18:35Z")

</div>

Happy of having being somehow useful. 🙂

So, I specified an algorithm (‘Tsit5()’) and I could go on.

(FYI, I also tried to directly `import DifferentialEquations`, then to add `DifferentialEquations.` prefix to any command (`solve`, `ìnit`…) otherwise they were no more ‘defined’ : but I still got the error with `DifferentialEquations.init`).

Now the problem is that the step function does not accept any argument exception made for the integrator.

```julia
step!(integrator,dt=time_steps[i]-time_steps[i-1],stop_at_tdt=true)

```

…results in:

```julia
MethodError: no method matching step!(::OrdinaryDiffEq.ODEIntegrator{Tsit5, true, Vector{Float64}, Nothing, Float64, Float64, Float64, Float64, Float64, Vector{Vector{Float64}}, ODESolution{Float64, 2, Vector{Vector{Float64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Vector{Float64}}}, ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, Float64, ODEFunction{true, typeof(xenon!), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, Tsit5, OrdinaryDiffEq.InterpolationData{ODEFunction{true, typeof(xenon!), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Vector{Vector{Float64}}, Vector{Float64}, Vector{Vector{Vector{Float64}}}, OrdinaryDiffEq.Tsit5Cache{Vector{Float64}, Vector{Float64}, Vector{Float64}, OrdinaryDiffEq.Tsit5ConstantCache{Float64, Float64}}}, DiffEqBase.DEStats}, ODEFunction{true, typeof(xenon!), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, OrdinaryDiffEq.Tsit5Cache{Vector{Float64}, Vector{Float64}, Vector{Float64}, OrdinaryDiffEq.Tsit5ConstantCache{Float64, Float64}}, OrdinaryDiffEq.DEOptions{Float64, Float64, Float64, Float64, PIController{Float64}, typeof(DiffEqBase.ODE_DEFAULT_NORM), typeof(LinearAlgebra.opnorm), Nothing, CallbackSet{Tuple{}, Tuple{}}, typeof(DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN), typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), typeof(DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK), DataStructures.BinaryMinHeap{Float64}, DataStructures.BinaryMinHeap{Float64}, Nothing, Nothing, Int64, Tuple{}, Tuple{}, Tuple{}}, Vector{Float64}, Float64, Nothing, OrdinaryDiffEq.DefaultInit}; dt=1.0, stop_at_tdt=true)

```

So, it is not accepting my “dt”, which is necessary in order to change the p value at the proper time…

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 22, 2022, 12:01am UTC](https://discourse.julialang.org/t/use-a-time-series-as-parameter-of-odeproblem/82945/14 "2022-06-22T00:01:33Z")

</div>

> [@Songio](#):
>
> `step!(integrator,dt=time_steps[i]-time_steps[i-1],stop_at_tdt=true)`

You wrote those as keyword arguments, not positional arguments. In Julia, keyword arguments are documented (and implemented) by being after a `;`, so `step!(integrator;dt[,stop_at_tdt=false])` would mean keyword. But

[https://diffeq.sciml.ai/stable/basics/integrator/#SciMLBase.step](https://diffeq.sciml.ai/stable/basics/integrator/#SciMLBase.step)!

These are positional (because the second is required for the third), so the syntax is:

```julia
step!(integrator,time_steps[i]-time_steps[i-1],true)

```
