# How to define a system of ODEs with @ode\_def and update the value of a variable using a function that depends on time?

**URL:** <https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404>\
**Category:** New to Julia\
**Tags:** question, numerics, symbolics, differentialequation\
**Created:** [May 5, 2023, 11:20pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404 "2023-05-05T23:20:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![atmyo4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/atmyo4/32/49587_2.png) [@atmyo4](https://discourse.julialang.org/u/atmyo4)\
**Post date:** [May 5, 2023, 11:20pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/1 "2023-05-05T23:20:40Z")

</div>

Hello, I’m new to Julia and I have a problem with my code. I am defining a system of differential equations using @ode\_def of ParameterizedFunctions.jl and I want to determine the value of a variable using a function. However, I only want to change the value of the variable if t \> 0. Doing this operation gives me an error because I am using the symbol `t` in a boolean context.

I know I could do this with a callback, but even though it doesn’t throw errors, it doesn’t give me the correct result.

What should I do? Is there a way to continue using @ode\_def or should I simply use a generic function to define the system? I would prefer to find a solution to continue using @ode\_def.

Here is the code:

```julia
using DifferentialEquations
using ParameterizedFunctions

# Solve odeFB
odeFB = @ode_def begin 
    dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi)
    dGi = (k4 * Gp) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
    dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
end Vmax Ge Km k2 k3 k4 k5 km2 km4 km5

x0 = ones(length(odeFB.syms))
p = (1400, 24.15, 1100, 5.3, 4, 2, 2.3, 5.3, 2, 2.3)
solFB = solve(ODEProblem(odeFB,x0,1000,p); reltol = 1e-12);

# External function to calculate a constant of the equation du[2] of the second system 
function f(t, solFB)
    if t > 0
        i = findfirst(times .>= t)
        return ((((solFB[1,i] - solFB[1,i-1]) / (solFB.t[i] - solFB.t[i-1])) * (t .- solFB.t[i-1])) .+ solFB[1,i-1])
    else 
        return solFB[1,1]
    end
end 

# Solve odeNF
odeNF = @ode_def begin 
    dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi)
    dGi = (k4*f(t, solFB)) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
    dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
end Vmax Ge Km k2 k3 k4 k5 k6 km2 km4 km5 

solNF = solve(ODEProblem(odeNF, x0, 1000, p); reltol = 1e-12);

```

---

<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 6, 2023, 12:21am UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/2 "2023-05-06T00:21:02Z")

</div>

You need to `@register_symbolic` it so that way it’s kept as a node in the symbolic graph.

```julia
using DifferentialEquations
using ParameterizedFunctions

# Solve odeFB
odeFB = @ode_def begin 
    dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi)
    dGi = (k4 * Gp) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
    dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
end Vmax Ge Km k2 k3 k4 k5 km2 km4 km5

x0 = ones(length(odeFB.syms))
p = (1400, 24.15, 1100, 5.3, 4, 2, 2.3, 5.3, 2, 2.3)
solFB = solve(ODEProblem(odeFB,x0,1000,p); reltol = 1e-12);

# External function to calculate a constant of the equation du[2] of the second system 
function f(t, solFB)
    if t > 0
        i = findfirst(solFB.t .>= t)
        return ((((solFB[1,i] - solFB[1,i-1]) / (solFB.t[i] - solFB.t[i-1])) * (t .- solFB.t[i-1])) .+ solFB[1,i-1])
    else 
        return solFB[1,1]
    end
end
f2(t) = f(t, solFB)

using Symbolics
@register_symbolic f2(t)

# Solve odeNF
odeNF = @ode_def begin 
    dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi)
    dGi = (k4 * f2(t)) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
    dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
end Vmax Ge Km k2 k3 k4 k5 km2 km4 km5
prob = ODEProblem(odeNF, x0, 1000, p); 
prob.f(x0,p,0.0)

solNF = solve(prob, reltol = 1e-12);

```

See [Function Registration and Tracing · Symbolics.jl](https://symbolics.juliasymbolics.org/stable/manual/functions/) for more details.

This is because ParameterizedFunctions.jl is implemented using ModelingToolkit.jl/Symbolics.jl, and this is a property of the symbolic library. Generally I wouldn’t recommend ParameterizedFunctions.jl that much these days except for very simple cases, but you can use this to make it do crazy things just by registering more functions to it.

---

<div class="post-metadata">

**Author:** ![atmyo4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/atmyo4/32/49587_2.png) [@atmyo4](https://discourse.julialang.org/u/atmyo4)\
**Post date:** [May 6, 2023, 12:43am UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/3 "2023-05-06T00:43:12Z")

</div>

It works perfectly! Thank you very much! Just out of curiosity, why wouldn’t you recommend using ParameterizedFunctions.jl anymore?

---

<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 6, 2023, 12:45pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/4 "2023-05-06T12:45:09Z")

</div>

Ehh it’s just very limited in comparison to ModelingToolkit without too many gains. People hit the wall of what it can do and ask for more features all of the time, and ModelingToolkit is the more flexible version. Nothing wrong with ParameterizedFunctions if you’re keeping it to simple things like this though.

---

<div class="post-metadata">

**Author:** ![atmyo4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/atmyo4/32/49587_2.png) [@atmyo4](https://discourse.julialang.org/u/atmyo4)\
**Post date:** [August 19, 2023, 2:30am UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/5 "2023-08-19T02:30:03Z")

</div>

Hey! I was playing with your solution, and it works perfectly until you change the second parameter from 24.15 to 18 (just to give an example; there is a whole range of parameters it does not work with). The error that I get is the following:

```julia
ERROR: LoadError: MethodError: Cannot `convert` an object of type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64

```

It’s really odd.

Anyway, thanks for helping me before!

---

<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, 2023, 5:52am UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/6 "2023-08-19T05:52:20Z")

</div>

That shouldn’t do anything, the exact numbers don’t matter in the tracing.

---

<div class="post-metadata">

**Author:** ![atmyo4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/atmyo4/32/49587_2.png) [@atmyo4](https://discourse.julialang.org/u/atmyo4)\
**Post date:** [August 19, 2023, 2:46pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/7 "2023-08-19T14:46:23Z")

</div>

Yes, I’m quite sure it has to do with the ODE solver, as the error doesn’t occur with certain algorithm, such as KenCarp4().

---

<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, 2023, 4:10pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/8 "2023-08-19T16:10:33Z")

</div>

This would require an MWE.

---

<div class="post-metadata">

**Author:** ![atmyo4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/atmyo4/32/49587_2.png) [@atmyo4](https://discourse.julialang.org/u/atmyo4)\
**Post date:** [August 19, 2023, 4:45pm UTC](https://discourse.julialang.org/t/how-to-define-a-system-of-odes-with-ode-def-and-update-the-value-of-a-variable-using-a-function-that-depends-on-time/98404/9 "2023-08-19T16:45:46Z")

</div>

Okay, here’s a MWE where a system of ODEs uses an external function that will always return zero to add it to its first equation, therefore the external function shouldn’t affect the solution. The first example is identical to the second, with the exception that in the second example, it’s specified that KenCarp4() should be used to solve the system.

> **Throws an error**
>
> ```julia
> using DifferentialEquations
> using ParameterizedFunctions
> 
> # External function
> function f(t)
> return t*0
> end
> 
> using Symbolics
> @register_symbolic f(t)
> 
> # ODE
> ode = @ode_def begin 
> dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi) + f(t)
> dGi = (k4 * Gp) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
> dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
> end Vmax Ge Km k2 k3 k4 k5 km2 km4 km5
> 
> x0 = ones(length(ode.syms))
> p = (1400, 18, 1100, 5.3, 4, 2, 2.3, 5.3, 2, 2.3)
> prob = ODEProblem(ode, x0, 1000, p); 
> 
> sol = solve(prob, reltol = 1e-12);
> 
> ```
> 
> Error:
> 
> ```julia
> ERROR: LoadError: MethodError: Cannot `convert` an object of type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64
> 
> ```

> **Works fine**
>
> ```julia
> using DifferentialEquations
> using ParameterizedFunctions
> 
> # External function 
> function f(t)
> return t*0
> end
> 
> using Symbolics
> @register_symbolic f(t)
> 
> # ODE
> ode = @ode_def begin 
> dGp = ((Vmax * Ge * Gp)/(Km + Gp)) - (k4 * Gp) - (k2 * A * Gp) + (km2 * A) + (km4 * Gi) + f(t)
> dGi = (k4 * Gp) - (k5 * Gi) - (km4 * Gi) + (km5 * A)
> dA = - (k3 * A) + (k5 * Gi) - (km5 * A)
> end Vmax Ge Km k2 k3 k4 k5 km2 km4 km5
> 
> x0 = ones(length(ode.syms))
> p = (1400, 18, 1100, 5.3, 4, 2, 2.3, 5.3, 2, 2.3)
> prob = ODEProblem(ode, x0, 1000, p); 
> 
> sol = solve(prob, KenCarp4(), reltol = 1e-12);
> 
> ```
