# Exogenous functions and data in ODE aren't working if modertly complicated

**URL:** https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678
**Category:** Numerics
**Tags:** question, diffeq
**Created:** [August 19, 2021, 3:08pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678 "2021-08-19T15:08:24Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Anthony](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anthony/32/23968_2.png) [@Anthony](https://discourse.julialang.org/u/Anthony)
#### Post date: [August 19, 2021, 3:08pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/1 "2021-08-19T15:08:25Z")

</div>

Yesterday [I posted about getting control inputs into an ODE](https://discourse.julialang.org/t/solving-ode-parameters-using-experimental-data-with-control-inputs/66614) and I got great advice. However, I’m running into an issue where the exogenous functions used don’t seem to work if they’re even moderately complicated.

Below is a minimal example. I have an ODE defined that pulls in a constant `c` and exogenous function `D_(t)`. If `D(t)` uses a simple condition, e.g., `time > 5`, it works as intended. If I add anything slightly more complicated, like another condition, e.g., `(time > 5) && (time < 6)`, it doesn’t appear to have any effect anymore. In my real project I’m trying to pull in values in D from data, but even just hard-coding a control signal does not seem to work. I’m not sure where I’m going wrong in this.

Minimal working example:

```julia
using DifferentialEquations
using ParameterizedFunctions
using Optim
using Plots
gr()

function D1(t)
    if (t > 5)
        return 0.1
    else
        return 0.0
    end
end
function D2(t)
    if (t > 5) && (t < 6)
        return 0.1
    else
        return 0.0
    end
end
p = [
    -0.1089 ;
    75.2304 ;
     2.3965
]
c = p[end]

sma_ode1 = @ode_def begin
    dT = a*T + b*D1(t) + c
end a b
sma_ode2 = @ode_def begin
    dT = a*T + b*D2(t) + c
end a b
u0 = [22.0]
p0 = p[1:2]
tspan = (0.0, 10.0)
prob1 = ODEProblem(sma_ode1, u0, tspan, p0)
prob2 = ODEProblem(sma_ode2, u0, tspan, p0)
sol1 = solve(prob1, Tsit5(), saveat=0.1)
sol2 = solve(prob2, Tsit5(), saveat=0.1)
p11 = plot(sol1, ylims=(0,50), title="Single condition")
p12 = plot(sol1.t, D1.(sol1.t))
p21 = plot(sol2, ylims=(0,50), title="Two conditions")
p22 = plot(sol2.t, D2.(sol2.t))
l = @layout [a b ; c d]
plot(p11, p21, p12, p22, layout = l)

```

Output:

 ![imagen](https://global.discourse-cdn.com/julialang/original/3X/e/e/eec4937deeb2f8330de4196b02ff2784a625c680.png)

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [August 19, 2021, 3:37pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/2 "2021-08-19T15:37:57Z")

</div>

The adaptive-timestep ODE methods take larger timesteps in smooth regions. In the first case, the forcing function stays on, and the solver notices that the forcing function has changed and backtracks to better capture the change. In the second case, the forcing function returns to zero, and the timestep was large enough to step right past the active time of the forcing function. You can force the solver to stop at the discontinuous timesteps with `tstops=[5.0, 6.0]`, decrease the maximum timestep, or change the forcing function with a [callback](https://diffeq.sciml.ai/dev/features/callback_functions/).

---

<div class="post-metadata">

### Author: ![Anthony](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anthony/32/23968_2.png) [@Anthony](https://discourse.julialang.org/u/Anthony)
#### Post date: [August 19, 2021, 3:49pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/3 "2021-08-19T15:49:11Z")

</div>

Awesome! Thank you very much for your help! So in the case of data (which looks similar, as the control signal for this experiment is largely just switching on and off) I suppose what I should do is set tstop to be points of discontinuity I detect just using the derivative of the control.

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [August 19, 2021, 3:50pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/4 "2021-08-19T15:50:12Z")

</div>

Note that `saveat` doesn’t force the ODE solver to step through all those times - it just interpolates the solution:  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/4/9/492e321ef912bf15b21423f32ed3ef02b74586ec.png)

With `tstops=[5, 6]`,  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/5/3/534453046ae3161915e9d11ad7bcbb3e666ee208.png)

---

<div class="post-metadata">

### Author: ![Anthony](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anthony/32/23968_2.png) [@Anthony](https://discourse.julialang.org/u/Anthony)
#### Post date: [August 19, 2021, 3:58pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/5 "2021-08-19T15:58:10Z")

</div>

If you don’t mind a related followup: I’m actually trying to use DiffEqParamEstim to estimate parameters `a` and `b`. Are you aware if this time step behavior affects optimizations as well? I don’t see a similar tstops parameter from the `optimize` routine or problem setup. Maybe this needs to become a separate question.

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [August 19, 2021, 4:04pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/6 "2021-08-19T16:04:14Z")

</div>

I haven’t used DiffEqParamEstim, but looking at the [docs](https://diffeqparamestim.sciml.ai/dev/methods/optimization_based_methods/#Standard-Nonlinear-Regression), you should be able to pass additional keyword arguments for the ODE solver when constructing the loss function.

---

<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: [August 19, 2021, 10:07pm UTC](https://discourse.julialang.org/t/exogenous-functions-and-data-in-ode-arent-working-if-modertly-complicated/66678/7 "2021-08-19T22:07:05Z")

</div>

And [Handling Instability When Solving ODE Problems - #5 by ChrisRackauckas](https://discourse.julialang.org/t/handling-instability-when-solving-ode-problems/9019/5) goes into some strategies for handling discontinuous inputs.
