# DifferentialEquations with nested functions + Callbacks

**URL:** <https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737>\
**Category:** New to Julia\
**Created:** [May 29, 2019, 2:32pm UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737 "2019-05-29T14:32:24Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [May 29, 2019, 2:32pm UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/1 "2019-05-29T14:32:24Z")

</div>

Hello, now that I (sort of) know how to [calculate differential equations with nested functions](https://discourse.julialang.org/t/how-to-use-differentialequations-with-complicated-equations/20740/19) I would like to learn how to use it with callbacks. Callbacks are used to run a differential equation to a certain point, changing the value of a parameter and then continue running. And that’s really handy when working with seasonal data.

I know how a callback looks like when using a differential equation that [does not have nested functions](https://discourse.julialang.org/t/is-there-a-way-to-run-differential-equations-to-a-specific-point-and-then-change-input-values-continue-running-and-graph-it-together/19232/8), but my experiments with a callback and differential equation with nested functions have failed so far.

The outline of the code (I will post the whole code if you want, but I don’t know how to make a MWE because there are many parts)

```julia
function FF (parameters)

function CalcG (parameters)

function dNdT (parameters) #change in nutrient 'biomass'
       something* CalcG (parameters)
end

function dPdT (parameters) #change in plant biomass
       something/ FF (parameters)+ CalcG (parameters)
end

function dAdT (parameters) #change in animal biomass
       function FF (parameters)
end

```

And then `dNdT`, `dPdT`, `dAdT` are placed together into one array and calculated at the same time:

```julia
function dBdT_test(dB, bioS, p, t) #where dB is change in biomass

    #extinction
    @. bioS[bioS<0.000001] = 0.0 #here I don't know if this should be placed before or after the equations
    @. dB[bioS<0.000001] = 0.0

    dN = dB[1:num_nutrient]
    dP = dB[num_nutrient+1:(arr_size-num_animal)]
    dA = dB[(arr_size-num_animal+1):arr_size]

    dB[1:num_nutrient] = dNdT(dN, D, S, N, K, v1, v2, r, bioS)
    dB[num_nutrient+1:(arr_size-num_animal)] = dPdT(dP, K, N, r, bioS, X, num_plant, num_animal, num_nutrient)
    dB[(arr_size-num_animal+1):arr_size] = dAdT(dA, foodWeb, e, bioS, X, num_plant, num_animal, num_nutrient, bm, b, h, ω, q)

    #extinction
    @. bioS[bioS<0.000001] = 0.0 
    @. dB[bioS<0.000001] = 0.0 #here I don't know if this should be placed before or after the equations

end

tspan = (0.0,500.0)
p = (foodWeb, num_plant, num_animal, num_nutrient, D, S, N, K, v1, v2, r, X, e, bm, b, h, ω, q)

prob = ODEProblem(dBdT,bioS,tspan,p)
sol=solve(prob)

```

Is it good to have `dNdT`, `dPdT`, `dAdT` as separate functions and then call them into `dBdT` ?

I only want to put a callback for a specific species (lets say species 42) in `dAdT`.

Should I place the callback into `function dAdT` or `function dBdT`?

I tried putting it into dBdT like so, but then f1 is not defined

```julia
dB[(arr_size-num_animal+1):arr_size] = dAdT_harvest(dA, foodWeb, e, bioS, X, num_plant, num_animal, num_nutrient, bm, b, h, ω, q) - (catch_co*bioS[42]*effort + f1)`

```

And the callback is

```julia
function condition(u,t,integrator)
  t == 200.
end
function affect!(integrator)
  for c in full_cache(integrator)
    integrator.p[21] = 0.01
  end
end
cb = DiscreteCallback(condition, affect!)

tspan = (0.0,500.0)

p = (foodWeb, num_plant, num_animal, num_nutrient, D, S, N, K, v1, v2, r, X, e, bm, b, h, ω, q, catch_co, effort, f1)

prob = ODEProblem(dBdT,bioS,tspan,p)
sol=solve(prob,callback=cb,tstops=[200.0])

```

Suggestions are greatly appreciated

---

<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:** [May 31, 2019, 1:09am UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/2 "2019-05-31T01:09:14Z")

</div>

There is no difference between putting code in functions or not, other than for aesthetics and composibility. That said, I’m not sure what your question is.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 3, 2019, 10:08am UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/3 "2019-06-03T10:08:29Z")

</div>

Apologies for not being clear.

When I try to introduce a callback into my (working) code, Julia gives an error that `f1` is not defined. I would like to know how to correctly add a callback as I can’t find a relatable example in the [callback tutorial](http://juliadiffeq.org/DiffEqTutorials.jl/html/introduction/callbacks_and_events.html).

The code is

```julia
function dBdT_harvest(dB, bioS, p, t)

    #extinction
    @. bioS[bioS<0.000001] = 0.0
    @. dB[bioS<0.000001] = 0.0

    dN = dB[1:num_nutrient]
    dP = dB[num_nutrient+1:(arr_size-num_animal)]
    dA = dB[(arr_size-num_animal+1):arr_size]

    dB[1:num_nutrient] = dNdT(dN, D, S, N, K, v1, v2, r, bioS)
    dB[num_nutrient+1:(arr_size-num_animal)] = dPdT(dP, K, N, r, bioS, X, num_plant, num_animal, num_nutrient)
    dB[(arr_size-num_animal+1):arr_size] = (dAdT(dA, foodWeb, e, bioS, X, num_plant, num_animal, num_nutrient, bm, b, h, ω, q) - (catch_co*bioS[42]*effort + f1)) # I introduce f1 here 

    #extinction
    @. bioS[bioS<0.000001] = 0.0
    @. dB[bioS<0.000001] = 0.0

end

function condition(u,t,integrator)
  t == 200.
end

function affect!(integrator)
  for c in full_cache(integrator) # I do not understand the purpose of this line
    integrator.p[21] = 0.01 # Here f1 is the 21st parameter
  end
end

cb = DiscreteCallback(condition, affect!)

tspan = (0.0,500.0)

p = (foodWeb, num_plant, num_animal, num_nutrient, D, S, N, K, v1, v2, r, X, e, bm, b, h, ω, q, catch_co, effort, f1) # the error happens here

prob = ODEProblem(dBdT_harvest,bioS,tspan,p)
sol=solve(prob,callback=cb,tstops=[200.0])

```

Error is `UndefVarError: f1 not defined in top-level scope at base\none`. I assume the issue is something with this part:

```julia
function affect!(integrator)
  for c in full_cache(integrator) 
    integrator.p[21] = 0.01
  end
end

```

---

<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 3, 2019, 11:22am UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/4 "2019-06-03T11:22:27Z")

</div>

> [@HelgavonLichtenstein](#):
>
> function affect!(integrator) for c in full\_cache(integrator) integrator.p[21] = 0.01 end end

```julia
function affect!(integrator)
  integrator.p[21] = 0.01
end

```

but that’s not the line causing your issue.

```julia
dB[(arr_size-num_animal+1):arr_size] = (dAdT(dA, foodWeb, e, bioS, X, num_plant, num_animal, num_nutrient, bm, b, h, ω, q) - (catch_co*bioS[42]*effort + f1)) # I introduce f1 here 

```

but `f1` isn’t defined, so 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 3, 2019, 11:48am UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/5 "2019-06-03T11:48:08Z")

</div>

I thought `f1` corresponds to

```julia
function condition(u,t,integrator)
  t == 200.
end

function affect!(integrator)
     integrator.p[21] = 0.01 # Here f1 is the 21st parameter
end

```

My goal is to change the value of `catch_co` to `0.01` at the `200`th time step.

---

<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 3, 2019, 11:56am UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/6 "2019-06-03T11:56:05Z")

</div>

You never said `f1 = ...` I don’t even know what `f1` is. All of `dN, D, S, N, K, v1, v2, r` are also not defined in your code. Are they from `p`? You need to write down any namings you come up with, otherwise both me and the computer will have no idea `f1 = p[21]`.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 3, 2019, 12:25pm UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/7 "2019-06-03T12:25:33Z")

</div>

I am trying to follow the examples [here](http://docs.juliadiffeq.org/latest/features/diffeq_arrays.html#Example:-A-Control-Problem-1) and [here](https://discourse.julialang.org/t/is-there-a-way-to-run-differential-equations-to-a-specific-point-and-then-change-input-values-continue-running-and-graph-it-together/19232/8) so I thought it was common to use `f1`.

Everything in the code is defined and works, except for `f1` which I now introduce as part of the callback. I will think about this some more and try to make my question more understandable.

---

<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 3, 2019, 12:32pm UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/8 "2019-06-03T12:32:29Z")

</div>

`f1` is a field in the array type in that example. You’re using normal arrays so it doesn’t exist.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 3, 2019, 3:02pm UTC](https://discourse.julialang.org/t/differentialequations-with-nested-functions-callbacks/24737/9 "2019-06-03T15:02:14Z")

</div>

Okay, I got it to run.

For people struggling with this,

First, make sure the parameter (not the thing/variable the differential equation is supposed to calculate) you are going to change is defined somewhere already, even if the starting value is 0)

For example, `catch_co = 0`

Then for the call back

```julia
function condition(u,t,integrator)
  t == 200.
end

```

Where `200` is the time step you want your parameter to change

Then you have to specify what parameter is changing and what it is changing to

```julia
function affect!(integrator)
  for c in full_cache(integrator)
    integrator.p[19] = 0.01
  end
end

```

Where `[19]` corresponds to the number of your parameter in your p list (see below), and it changes to a value of `0.01`.

```julia
cb = DiscreteCallback(condition, affect!)

tspan = (0.0,500.0)

p = (foodWeb, num_plant, num_animal, num_nutrient, D, S, N, K, v1, v2, r, X, e, bm, b, h, ω, q, catch_co, effort) 
#In this case `catch_co = 0` is the 19th parameter in the list.

prob = ODEProblem(dBdT_harvest,bioS,tspan,p)
sol=solve(prob,callback=cb,tstops=[200.0])

```

So that’s how a callback with nested functions is done.
