ModelingToolkit.jl icon indicating copy to clipboard operation
ModelingToolkit.jl copied to clipboard

Sanity type-checking for equations

Open lamorton opened this issue 2 years ago • 1 comments

Guess where the error message happens from in this snippet:

using ModelingToolkit
@variables t x(t) 
@parameters a = 1
D = Differential(t)
Dx = D(x)
eqs = [ Dx ~ "a"]  # Ooopsy....
sys = ODESystem(eqs, name = :sys) 
p = [a]
tspan = [0, 1]
u0 = [1]
prob = ODEProblem(sys, u0, tspan p)
sol = solve(prob, Tsit5())  
Error message

On the final line, the generated function tries to assign a string to a float.

ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64
Closest candidates are:
  convert(::Type{R}, ::T) where {R<:Real, T<:ReverseDiff.TrackedReal} at C:\Users\lucas\.julia\packages\ReverseDiff\5MMPp\src\tracked.jl:260        
  convert(::Type{T}, ::Gain) where T<:Real at C:\Users\lucas\.julia\packages\Unitful\SUQzL\src\logarithm.jl:62
  convert(::Type{T}, ::Level) where T<:Real at C:\Users\lucas\.julia\packages\Unitful\SUQzL\src\logarithm.jl:22
  ...
Stacktrace:
  [1] setindex!(A::Vector{Float64}, x::String, i1::Int64)
    @ Base .\array.jl:966
  [2] macro expansion
    @ C:\Users\lucas\.julia\packages\SymbolicUtils\qulQp\src\code.jl:394 [inlined]
  [3] macro expansion
    @ C:\Users\lucas\.julia\packages\Symbolics\J8IHJ\src\build_function.jl:504 [inlined]
  [4] macro expansion
    @ C:\Users\lucas\.julia\packages\SymbolicUtils\qulQp\src\code.jl:351 [inlined]
  [5] macro expansion
    @ C:\Users\lucas\.julia\packages\RuntimeGeneratedFunctions\KrkGo\src\RuntimeGeneratedFunctions.jl:129 [inlined]
  [6] macro expansion
    @ .\none:0 [inlined]
  [7] generated_callfunc
    @ .\none:0 [inlined]
  [8] (::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)})(::Vector{Float64}, ::Vector{Float64}, ::Vector{Num}, ::Float64)
    @ RuntimeGeneratedFunctions C:\Users\lucas\.julia\packages\RuntimeGeneratedFunctions\KrkGo\src\RuntimeGeneratedFunctions.jl:117
  [9] (::ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}})(du::Vector{Float64}, u::Vector{Float64}, p::Vector{Num}, t::Float64)
    @ ModelingToolkit C:\Users\lucas\Documents\Code\Jdev\ModelingToolkit\src\systems\diffeqs\abstractodesystem.jl:268
 [10] (::ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem})(::Vector{Float64}, ::Vararg{Any})
    @ SciMLBase C:\Users\lucas\.julia\packages\SciMLBase\UY87O\src\scimlfunctions.jl:1655
 [11] initialize!(integrator::OrdinaryDiffEq.ODEIntegrator{Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, true, Vector{Float64}, Nothing, Float64, Vector{Num}, Float64, Float64, Float64, Float64, Vector{Vector{Float64}}, ODESolution{Float64, 2, Vector{Vector{Float64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Vector{Float64}}}, ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, Vector{Num}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, 
Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), 
typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, OrdinaryDiffEq.InterpolationData{ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, 
Vector{Vector{Float64}}, Vector{Float64}, Vector{Vector{Vector{Float64}}}, OrdinaryDiffEq.Tsit5Cache{Vector{Float64}, Vector{Float64}, Vector{Float64}, OrdinaryDiffEq.Tsit5ConstantCache{Float64, Float64}, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}}, DiffEqBase.DEStats}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, OrdinaryDiffEq.Tsit5Cache{Vector{Float64}, Vector{Float64}, Vector{Float64}, OrdinaryDiffEq.Tsit5ConstantCache{Float64, Float64}, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, OrdinaryDiffEq.DEOptions{Float64, Float64, Float64, Float64, PIController{Rational{Int64}}, typeof(DiffEqBase.ODE_DEFAULT_NORM), typeof(LinearAlgebra.opnorm), Nothing, CallbackSet{Tuple{}, Tuple{}}, typeof(DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN), typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), typeof(DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK), DataStructures.BinaryHeap{Float64, DataStructures.FasterForward}, DataStructures.BinaryHeap{Float64, DataStructures.FasterForward}, Nothing, Nothing, Int64, Tuple{}, Tuple{}, Tuple{}}, Vector{Float64}, Float64, Nothing, OrdinaryDiffEq.DefaultInit}, cache::OrdinaryDiffEq.Tsit5Cache{Vector{Float64}, Vector{Float64}, Vector{Float64}, OrdinaryDiffEq.Tsit5ConstantCache{Float64, Float64}, typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False})
    @ OrdinaryDiffEq C:\Users\lucas\.julia\packages\OrdinaryDiffEq\gCvy4\src\perform_step\low_order_rk_perform_step.jl:627
 [12] __init(prob::ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, Vector{Num}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, alg::Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), 
typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, timeseries_init::Tuple{}, ts_init::Tuple{}, ks_init::Tuple{}, recompile::Type{Val{true}}; saveat::Tuple{}, tstops::Tuple{}, d_discontinuities::Tuple{}, save_idxs::Nothing, save_everystep::Bool, save_on::Bool, save_start::Bool, save_end::Nothing, callback::Nothing, dense::Bool, calck::Bool, dt::Float64, dtmin::Nothing, dtmax::Float64, force_dtmin::Bool, adaptive::Bool, gamma::Rational{Int64}, abstol::Nothing, reltol::Nothing, qmin::Rational{Int64}, qmax::Int64, qsteady_min::Int64, qsteady_max::Int64, beta1::Nothing, beta2::Nothing, qoldinit::Rational{Int64}, controller::Nothing, fullnormalize::Bool, failfactor::Int64, maxiters::Int64, internalnorm::typeof(DiffEqBase.ODE_DEFAULT_NORM), internalopnorm::typeof(LinearAlgebra.opnorm), isoutofdomain::typeof(DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN), unstable_check::typeof(DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK), verbose::Bool, timeseries_errors::Bool, dense_errors::Bool, advance_to_tstop::Bool, stop_at_next_tstop::Bool, initialize_save::Bool, progress::Bool, progress_steps::Int64, progress_name::String, progress_message::typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), userdata::Nothing, allow_extrapolation::Bool, initialize_integrator::Bool, alias_u0::Bool, alias_du0::Bool, initializealg::OrdinaryDiffEq.DefaultInit, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})        
    @ OrdinaryDiffEq C:\Users\lucas\.julia\packages\OrdinaryDiffEq\gCvy4\src\solve.jl:454
 [13] __init (repeats 5 times)
    @ C:\Users\lucas\.julia\packages\OrdinaryDiffEq\gCvy4\src\solve.jl:9 [inlined]
 [14] #__solve#562
    @ C:\Users\lucas\.julia\packages\OrdinaryDiffEq\gCvy4\src\solve.jl:4 [inlined]
 [15] __solve
    @ C:\Users\lucas\.julia\packages\OrdinaryDiffEq\gCvy4\src\solve.jl:1 [inlined]
 [16] #solve_call#24
    @ C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:451 [inlined]
 [17] solve_call(_prob::ODEProblem{Vector{Float64}, Tuple{Float64, Float64}, true, Vector{Num}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, 
Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, args::Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False})
    @ DiffEqBase C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:421
 [18] solve_up(prob::ODEProblem{Vector{Float64}, Tuple{Int64, Int64}, true, Vector{Num}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, 
Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, sensealg::Nothing, u0::Vector{Float64}, p::Vector{Num}, args::Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ DiffEqBase C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:814
 [19] solve_up
    @ C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:787 [inlined]
 [20] #solve#29
    @ C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:784 [inlined]
 [21] solve(prob::ODEProblem{Vector{Float64}, Tuple{Int64, Int64}, true, Vector{Num}, ODEFunction{true, ModelingToolkit.var"#f#462"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0xc8f06a07, 0xff73569b, 0x165df38c, 0xd1c8f94f, 0x48d5ca6e)}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2, :t), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x1eb0efba, 0xf6ec394d, 
0xa23bcd8c, 0xca8ff638, 0x06028518)}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Symbol, ModelingToolkit.var"#472#generated_observed#469"{Bool, ODESystem, Dict{Any, Any}}, Nothing, ODESystem}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, args::Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False})
    @ DiffEqBase C:\Users\lucas\.julia\packages\DiffEqBase\WDtlB\src\solve.jl:767
 [22] top-level scope
    @ REPL[101]:1

In more realistic cases, some transformation/validation is going to choke first. It would be nice to have some guarantees about what's coming down the pipe to those things. Also, then the error message would point to the real problem. (I have unit validation in mind, but I'm sure structural_simplify has expectations about the types of terms in equations as well.)

lamorton avatar Aug 28 '22 18:08 lamorton

This could be handled via a type constraint on Equation https://github.com/JuliaSymbolics/Symbolics.jl/blob/ab7e1aa725f5599e1fb9a9b6e76beb5e392f820c/src/equations.jl#L33-L37

ValentinKaisermayer avatar Sep 01 '22 18:09 ValentinKaisermayer

Upstream issue. Tracking in Symbolics

ChrisRackauckas avatar Feb 22 '24 16:02 ChrisRackauckas