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:
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);
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.
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.
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:
ERROR: LoadError: MethodError: Cannot `convert` an object of type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64
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
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:
ERROR: LoadError: MethodError: Cannot `convert` an object of type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64
Works fine
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);