Skip to content

Support save_idxs with symbolic indexing #581

@TorkelE

Description

@TorkelE

Compiling a list of stuff that has been broken since he latest update. Noteworthy is that remake fails in diverse way depending on what problem you are using. Also, the new getp and setp interface functions are a bit weird (see SciML/SymbolicIndexingInterface.jl#24 for more details).

There is a lot of repetitive code in here, however, there are some unusual cases where SDE solutions fail for plotting, so probably make sense to go through it all.

Everything that does not have a comment is working fine. Lines with potential errors or weird behaviours are commented.

using Catalyst, OrdinaryDiffEq, StochasticDiffEq, JumpProcesses, NonlinearSolve, Plots
import ModelingToolkit: getp, setp

model = complete(@reaction_network begin
    (kp,kd), 0 <--> X
    (k1,k2), X <--> Y
end)
@unpack X, Y, kp, kd, k1, k2 = model

u0 = [X => 0.1, Y => 0.0]
tspan = (0.0, 10.0)
ps = [kp => 1.0, kd => 0.2, k1 => 1.0, k2 => 2.0]

# ODEProblem
oprob = ODEProblem(model, u0, tspan, ps)
oprob[X]
oprob[model.X]
oprob[:X]
oprob[[X,Y]]
oprob[[model.X,model.Y]]
oprob[[:X,:Y]]
oprob[(X,Y)]                # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
oprob[(model.X,model.Y)]    # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
oprob[(:X,:Y)]              # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.

oprob[X] = 0.2
oprob[model.X] = 0.3
oprob[:X] = 0.4

# Yes, here and in alter cases the first 3 have the intended behaviour, but still feels like a really weird choice of function name, see previous comment.
getp(oprob, kp) # Returns a SymbolicIndexingInterface struct.
getp(oprob, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(oprob, :kp) # Returns a SymbolicIndexingInterface struct.
getp(oprob, kp)(oprob)
getp(oprob, model.kp)(oprob)
getp(oprob, :kp)(oprob)

setp(oprob, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(oprob, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(oprob, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(oprob, kp)(oprob, 5.0)
setp(oprob, model.kp)(oprob, 6.0)
setp(oprob, :kp)(oprob, 7.0)

remake(oprob; u0 = [X => 0.2, Y => 0.2]).u0
remake(oprob; u0 = [model.X => 0.3, model.Y => 0.3]).u0
remake(oprob; u0 = [:X => 0.4, :Y => 0.4]).u0 # Does not update properly.
remake(oprob; u0 = [X => 0.5]).u0
remake(oprob; u0 = [model.X => 0.6]).u0
remake(oprob; u0 = [:X => 0.7]).u0 # Does not update properly.

remake(oprob; p = [kp => 0.1, kd => 0.1, k1 => 0.1, k2 => 0.1]).p
remake(oprob; p = [model.kp => 0.2, model.kd => 0.2, model.k1 => 0.2, model.k2 => 0.2]).p
remake(oprob; p = [:kp => 0.3, :kd => 0.3, :k1 => 0.3, :k2 => 0.3]).p # ERROR: ArgumentError: Any[kd, k1, k2] are missing from the variable map.
remake(oprob; p = [kp => 0.4]).p # ERROR: ArgumentError: SymbolicUtils.BasicSymbolic{Real}[kd, k1, k2] are missing from the variable map.
remake(oprob; p = [model.kp => 0.5]).p # ERROR: ArgumentError: SymbolicUtils.BasicSymbolic{Real}[kd, k1, k2] are missing from the variable map.
remake(oprob; p = [:kp => 0.6]).p # ERROR: ArgumentError: Any[kd, k1, k2] are missing from the variable map.

# SDEProblem
sprob = SDEProblem(model, u0, tspan, ps)
sprob[X]
sprob[model.X]
sprob[:X]
sprob[[X,Y]]
sprob[[model.X,model.Y]]
sprob[[:X,:Y]]
sprob[(X,Y)]                # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
sprob[(model.X,model.Y)]    # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
sprob[(:X,:Y)]              # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.

sprob[X] = 0.2
sprob[model.X] = 0.3
sprob[:X] = 0.4

getp(sprob, kp) # Returns a SymbolicIndexingInterface struct.
getp(sprob, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(sprob, :kp) # Returns a SymbolicIndexingInterface struct.
getp(sprob, kp)(sprob)
getp(sprob, model.kp)(sprob)
getp(sprob, :kp)(sprob)

setp(sprob, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(sprob, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(sprob, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(sprob, kp)(sprob, 5.0)
setp(sprob, model.kp)(sprob, 6.0)
setp(sprob, :kp)(sprob, 7.0)

remake(sprob; u0 = [X => 0.2, Y => 0.2]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; u0 = [model.X => 0.3, model.Y => 0.3]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; u0 = [:X => 0.4, :Y => 0.4]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; u0 = [X => 0.5]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(sprob; u0 = [model.X => 0.6]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(sprob; u0 = [:X => 0.7]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.

remake(sprob; p = [kp => 0.1, kd => 0.1, k1 => 0.1, k2 => 0.1]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; p = [model.kp => 0.2, model.kd => 0.2, model.k1 => 0.2, model.k2 => 0.2]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; p = [:kp => 0.3, :kd => 0.3, :k1 => 0.3, :k2 => 0.3]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(sprob; p = [kp => 0.4]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(sprob; p = [model.kp => 0.5]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(sprob; p = [:kp => 0.6]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.

# DiscreteProblem
dprob = DiscreteProblem(model, [X => 1, Y => 0], tspan, ps)
dprob[X]
dprob[model.X]
dprob[:X]
dprob[[X,Y]]
dprob[[model.X,model.Y]]
dprob[[:X,:Y]]
dprob[(X,Y)]                # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
dprob[(model.X,model.Y)]    # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
dprob[(:X,:Y)]              # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.

dprob[X] = 2
dprob[model.X] = 3
dprob[:X] = 4

getp(dprob, kp) # Returns a SymbolicIndexingInterface struct.
getp(dprob, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(dprob, :kp) # Returns a SymbolicIndexingInterface struct.
getp(dprob, kp)(dprob)
getp(dprob, model.kp)(dprob)
getp(dprob, :kp)(dprob)

setp(dprob, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(dprob, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(dprob, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(dprob, kp)(sprob, 5.0)
setp(dprob, model.kp)(sprob, 6.0)
setp(dprob, :kp)(sprob, 7.0)

remake(dprob; u0 = [X => 0.2, Y => 0.2]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; u0 = [model.X => 0.3, model.Y => 0.3]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; u0 = [:X => 0.4, :Y => 0.4]).u0 # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; u0 = [X => 0.5]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; u0 = [model.X => 0.6]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; u0 = [:X => 0.7]).u0 # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.

remake(dprob; p = [kp => 0.1, kd => 0.1, k1 => 0.1, k2 => 0.1]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [model.kp => 0.2, model.kd => 0.2, model.k1 => 0.2, model.k2 => 0.2]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [:kp => 0.3, :kd => 0.3, :k1 => 0.3, :k2 => 0.3]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [kp => 0.4]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; p = [model.kp => 0.5]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; p = [:kp => 0.6]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.

# JumpProblem
jprob = JumpProblem(model, dprob, Direct())
jprob[X]
jprob[model.X]
jprob[:X]
jprob[[X,Y]]
jprob[[model.X,model.Y]]
jprob[[:X,:Y]]
jprob[(X,Y)]                # Error. Not really needed, but supported for solutions.
jprob[(model.X,model.Y)]    # Error. Not really needed, but supported for solutions.
jprob[(:X,:Y)]              # Error. Not really needed, but supported for solutions.

jprob[X] = 2
jprob[model.X] = 3
jprob[:X] = 4

getp(jprob, kp) # ERROR: type JumpProblem has no field f
getp(jprob, model.kp) # ERROR: type JumpProblem has no field f
getp(jprob, :kp) # ERROR: type JumpProblem has no field f
getp(jprob, kp)(jprob) # ERROR: type JumpProblem has no field f
getp(jprob, model.kp)(jprob) # ERROR: type JumpProblem has no field f
getp(jprob, :kp)(jprob) # ERROR: type JumpProblem has no field f

setp(jprob, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(jprob, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(jprob, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(jprob, kp)(jprob, 5.0) # ERROR: type JumpProblem has no field f
setp(jprob, model.kp)(jprob, 6.0) # ERROR: type JumpProblem has no field f
setp(jprob, :kp)(jprob, 7.0) # ERROR: type JumpProblem has no field f

remake(jprob; u0 = [X => 0.2, Y => 0.2]).u0 # ERROR: type JumpProblem has no field u0
remake(jprob; u0 = [model.X => 0.3, model.Y => 0.3]).u0 # ERROR: type JumpProblem has no field u0
remake(jprob; u0 = [:X => 0.4, :Y => 0.4]).u0 # ERROR: type JumpProblem has no field u0
remake(jprob; u0 = [X => 0.5]).u0 # ERROR: type JumpProblem has no field u0
remake(jprob; u0 = [model.X => 0.6]).u0 # ERROR: type JumpProblem has no field u0
remake(jprob; u0 = [:X => 0.7]).u0 # ERROR: type JumpProblem has no field u0

remake(dprob; p = [kp => 0.1, kd => 0.1, k1 => 0.1, k2 => 0.1]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [model.kp => 0.2, model.kd => 0.2, model.k1 => 0.2, model.k2 => 0.2]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [:kp => 0.3, :kd => 0.3, :k1 => 0.3, :k2 => 0.3]).p # Makes u0 a vector of pairs (should be a normal vector).
remake(dprob; p = [kp => 0.4]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; p = [model.kp => 0.5]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.
remake(dprob; p = [:kp => 0.6]).p # Makes u0 a vector of pairs (should be a normal vector). Also makes it a vector with value for X only.

# NonlinearProblem
nlprob = NonlinearProblem(model, u0, ps)
nlprob[X]
nlprob[model.X]
nlprob[:X]
nlprob[[X,Y]]
nlprob[[model.X,model.Y]]
nlprob[[:X,:Y]]
nlprob[(X,Y)]                # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
nlprob[(model.X,model.Y)]    # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.
nlprob[(:X,:Y)]              # ERROR: Invalid indexing of problem. Not really needed, but supported for solutions and integrators.

nlprob[X] = 0.2
nlprob[model.X] = 0.3
nlprob[:X] = 0.4

getp(nlprob, kp) # Returns a SymbolicIndexingInterface struct.
getp(nlprob, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(nlprob, :kp) # Returns a SymbolicIndexingInterface struct.
getp(nlprob, kp)(nlprob)
getp(nlprob, model.kp)(nlprob)
getp(nlprob, :kp)(nlprob)

setp(nlprob, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(nlprob, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(nlprob, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(nlprob, kp)(nlprob, 5.0)
setp(nlprob, model.kp)(nlprob, 6.0)
setp(nlprob, :kp)(nlprob, 7.0)

remake(nlprob; u0 = [X => 0.2, Y => 0.2]).u0
remake(nlprob; u0 = [model.X => 0.3, model.Y => 0.3]).u0
remake(nlprob; u0 = [:X => 0.4, :Y => 0.4]).u0 # Does not update properly.
remake(nlprob; u0 = [X => 0.5]).u0
remake(nlprob; u0 = [model.X => 0.6]).u0
remake(nlprob; u0 = [:X => 0.7]).u0 # Does not update properly.

remake(nlprob; p = [kp => 0.1, kd => 0.1, k1 => 0.1, k2 => 0.1]).p
remake(nlprob; p = [model.kp => 0.2, model.kd => 0.2, model.k1 => 0.2, model.k2 => 0.2]).p
remake(nlprob; p = [:kp => 0.3, :kd => 0.3, :k1 => 0.3, :k2 => 0.3]).p  # Does not update properly.
remake(nlprob; p = [kp => 0.4]).p
remake(nlprob; p = [model.kp => 0.5]).p
remake(nlprob; p = [:kp => 0.6]).p  # Does not update properly.


# Integrator
using DifferentialEquations
integrator = init(oprob)

ointegrator = init(ODEProblem(model, u0, tspan, ps))
ointegrator[X]
ointegrator[model.X]
ointegrator[:X]
ointegrator[[X,Y]]
ointegrator[[model.X,model.Y]]
ointegrator[[:X,:Y]]
ointegrator[(X,Y)]              
ointegrator[(model.X,model.Y)] 
ointegrator[(:X,:Y)] 

ointegrator[X] = 0.2
ointegrator[model.X] = 0.3
ointegrator[:X] = 0.4

getp(ointegrator, kp) # Returns a SymbolicIndexingInterface struct.
getp(ointegrator, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(ointegrator, :kp) # Returns a SymbolicIndexingInterface struct.
getp(ointegrator, kp)(ointegrator)
getp(ointegrator, model.kp)(ointegrator)
getp(ointegrator, :kp)(ointegrator)

setp(ointegrator, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(ointegrator, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(ointegrator, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(ointegrator, kp)(ointegrator, 2.0)
setp(ointegrator, model.kp)(ointegrator, 3.0)
setp(ointegrator, :kp)(ointegrator, 4.0)

sintegrator = init(SDEProblem(model, u0, tspan, ps))
sintegrator[X]
sintegrator[model.X]
sintegrator[:X]
sintegrator[[X,Y]]
sintegrator[[model.X,model.Y]]
sintegrator[[:X,:Y]]
sintegrator[(X,Y)]              
sintegrator[(model.X,model.Y)] 
sintegrator[(:X,:Y)] 

sintegrator[X] = 0.2
sintegrator[model.X] = 0.3
sintegrator[:X] = 0.4

getp(sintegrator, kp) # Returns a SymbolicIndexingInterface struct.
getp(sintegrator, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(sintegrator, :kp) # Returns a SymbolicIndexingInterface struct.
getp(sintegrator, kp)(sintegrator)
getp(sintegrator, model.kp)(sintegrator)
getp(sintegrator, :kp)(sintegrator)

setp(sintegrator, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(sintegrator, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(sintegrator, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(sintegrator, kp)(sintegrator, 2.0)
setp(sintegrator, model.kp)(sintegrator, 3.0)
setp(sintegrator, :kp)(sintegrator, 4.0)

jintegrator = init(jprob, SSAStepper())
jintegrator[X]
jintegrator[model.X]
jintegrator[:X]
jintegrator[[X,Y]]
jintegrator[[model.X,model.Y]]
jintegrator[[:X,:Y]]
jintegrator[(X,Y)]              
jintegrator[(model.X,model.Y)] 
jintegrator[(:X,:Y)] 

jintegrator[X] = 2
jintegrator[model.X] = 3
jintegrator[:X] = 4

getp(jintegrator, kp) # Returns a SymbolicIndexingInterface struct.
getp(jintegrator, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(jintegrator, :kp) # Returns a SymbolicIndexingInterface struct.
getp(jintegrator, kp)(jintegrator)
getp(jintegrator, model.kp)(jintegrator)
getp(jintegrator, :kp)(jintegrator)

setp(jintegrator, kp, 2.0) # ERROR: MethodError: no method matching setp(...
setp(jintegrator, model.kp, 3.0) # ERROR: MethodError: no method matching setp(...
setp(jintegrator, :kp, 4.0) # ERROR: MethodError: no method matching setp(...
setp(jintegrator, kp)(jintegrator, 2.0)
setp(jintegrator, model.kp)(jintegrator, 3.0)
setp(jintegrator, :kp)(jintegrator, 4.0)

# Solve command
solve(oprob, Tsit5(); save_idxs=[X]) # ERROR: TypeError: non-boolean (Num) used in boolean context
solve(sprob, ImplicitEM(); save_idxs=[X]) # ERROR: TypeError: non-boolean (Num) used in boolean context
solve(jprob, SSAStepper(); save_idxs=[X]) # ERROR: MethodError: no method matching __init(::JumpProblem{...

solve(oprob, Tsit5(); save_idxs=[model.X]) # ERROR: TypeError: non-boolean (Num) used in boolean context
solve(sprob, ImplicitEM(); save_idxs=[model.X]) # ERROR: TypeError: non-boolean (Num) used in boolean context
solve(jprob, SSAStepper(); save_idxs=[model.X]) # ERROR: MethodError: no method matching __init(::JumpProblem{

solve(oprob, Tsit5(); save_idxs=[:X]) # ERROR: ArgumentError: unable to check bounds for indices of type Symbol
solve(sprob, ImplicitEM(); save_idxs=[:X]) # ERROR: ArgumentError: unable to check bounds for indices of type Symbol
solve(jprob, SSAStepper(); save_idxs=[:X]) # ERROR: MethodError: no method matching __init(::JumpProblem{true, 

# Fore reference, normal indexing also fails here:
solve(jprob, SSAStepper(); save_idxs=[1]) # ERROR: MethodError: no method matching __init(::JumpProblem{true, 

# Solution
osol = solve(oprob, Tsit5())
ssol = solve(sprob, ImplicitEM())
jsol = solve(jprob, SSAStepper())
nlsol = solve(nlprob, NewtonRaphson())

osol[X]
osol[model.X]
osol[:X]
osol[[X,Y]]
osol[[model.X,model.Y]]
osol[[:X,:Y]]
osol[(X,Y)]
osol[(model.X,model.Y)]
osol[(:X,:Y)]

getp(osol, kp) # Returns a SymbolicIndexingInterface struct.
getp(osol, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(osol, :kp) # Returns a SymbolicIndexingInterface struct.
getp(osol, kp)(osol)
getp(osol, model.kp)(osol)
getp(osol, :kp)(osol)

ssol[X]
ssol[model.X]
ssol[:X]
ssol[[X,Y]]
ssol[[model.X,model.Y]]
ssol[[:X,:Y]]
ssol[(X,Y)]
ssol[(model.X,model.Y)]
ssol[(:X,:Y)]

getp(ssol, kp) # Returns a SymbolicIndexingInterface struct.
getp(ssol, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(ssol, :kp) # Returns a SymbolicIndexingInterface struct.
getp(ssol, kp)(osol)
getp(ssol, model.kp)(osol)
getp(ssol, :kp)(osol)

jsol[X]
jsol[model.X]
jsol[:X]
jsol[[X,Y]]
jsol[[model.X,model.Y]]
jsol[[:X,:Y]]
jsol[(X,Y)]
jsol[(model.X,model.Y)]
jsol[(:X,:Y)]

getp(jsol, kp) # Returns a SymbolicIndexingInterface struct.
getp(jsol, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(jsol, :kp) # Returns a SymbolicIndexingInterface struct.
getp(jsol, kp)(osol)
getp(jsol, model.kp)(osol)
getp(jsol, :kp)(osol)

nlsol[X]
nlsol[model.X]
nlsol[:X]
nlsol[[X,Y]]
nlsol[[model.X,model.Y]]
nlsol[[:X,:Y]]
nlsol[(X,Y)] # ERROR: Invalid indexing of solution
nlsol[(model.X,model.Y)] # ERROR: Invalid indexing of solution
nlsol[(:X,:Y)] # ERROR: Invalid indexing of solution

getp(nlsol, kp) # Returns a SymbolicIndexingInterface struct.
getp(nlsol, model.kp) # Returns a SymbolicIndexingInterface struct.
getp(nlsol, :kp) # Returns a SymbolicIndexingInterface struct.
getp(nlsol, kp)(osol)
getp(nlsol, model.kp)(osol)
getp(nlsol, :kp)(osol)


# Plot command
plot(osol; idxs = [X])
plot(osol; idxs = [model.X])
plot(osol; idxs = [:X])

plot(ssol; idxs = [X]) # ERROR: ArgumentError: invalid index: X(t) of type 
plot(ssol; idxs = [model.X]) # ERROR: ArgumentError: invalid index: X(t) of type 
plot(ssol; idxs = [:X]) # ERROR: ArgumentError: invalid index: :X of type Symbol

plot(jsol; idxs = [X])
plot(jsol; idxs = [model.X])
plot(jsol; idxs = [:X])

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions