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);
You need to @register_symbolic
it so that way it’s kept as a node in the symbolic graph.
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 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.
1 Like
It works perfectly! Thank you very much! Just out of curiosity, why wouldn’t you recommend using ParameterizedFunctions.jl anymore?
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.
1 Like