From db458aee48e3ed3e36340e6f6bfdff68b69b8d8b Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 9 May 2022 10:11:06 +0200 Subject: [PATCH] handle empty events --- src/systems/abstractsystem.jl | 7 +++-- test/root_equations.jl | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/systems/abstractsystem.jl b/src/systems/abstractsystem.jl index 3843d497f0..418c2b53d9 100644 --- a/src/systems/abstractsystem.jl +++ b/src/systems/abstractsystem.jl @@ -170,6 +170,7 @@ struct SymbolicContinuousCallback end Base.:(==)(e1::SymbolicContinuousCallback, e2::SymbolicContinuousCallback) = isequal(e1.eqs, e2.eqs) && isequal(e1.affect, e2.affect) +Base.isempty(cb::SymbolicContinuousCallback) = isempty(cb.eqs) to_equation_vector(eq::Equation) = [eq] to_equation_vector(eqs::Vector{Equation}) = eqs @@ -482,11 +483,13 @@ end function continuous_events(sys::AbstractSystem) obs = get_continuous_events(sys) + filter(!isempty, obs) systems = get_systems(sys) - [obs; - reduce(vcat, + cbs = [obs; + reduce(vcat, (map(o->namespace_equation(o, s), continuous_events(s)) for s in systems), init=SymbolicContinuousCallback[])] + filter(!isempty, cbs) end Base.@deprecate default_u0(x) defaults(x) false diff --git a/test/root_equations.jl b/test/root_equations.jl index f5a12f1236..2bb9d71dd3 100644 --- a/test/root_equations.jl +++ b/test/root_equations.jl @@ -211,6 +211,8 @@ affect = [v ~ -v] @test getfield(ball, :continuous_events)[] == SymbolicContinuousCallback(Equation[x ~ 0], Equation[v ~ -v]) ball = structural_simplify(ball) +@test length(ModelingToolkit.continuous_events(ball)) == 1 + tspan = (0.0,5.0) prob = ODEProblem(ball, Pair[], tspan) sol = solve(prob,Tsit5()) @@ -305,3 +307,52 @@ prob = ODAEProblem(sys, zeros(2), (0.0, 5.1)) sol = solve(prob, Tsit5()) @test all(minimum((0:0.1:5) .- sol.t', dims=2) .< 0.0001) # test that the solver stepped every 0.1s as dictated by event @test sol([0.25])[vmeasured][] == sol([0.23])[vmeasured][] # test the hold property + + + +## https://github.com/SciML/ModelingToolkit.jl/issues/1528 +Dₜ = Differential(t) + +@parameters u(t) [input=true] # Indicate that this is a controlled input +@parameters y(t) [output=true] # Indicate that this is a measured output + +function Mass(; name, m = 1.0, p = 0, v = 0) + ps = @parameters m=m + sts = @variables pos(t)=p vel(t)=v + eqs = Dₜ(pos) ~ vel + ODESystem(eqs, t, [pos, vel], ps; name) +end +function Spring(; name, k = 1e4) + ps = @parameters k=k + @variables x(t)=0 # Spring deflection + ODESystem(Equation[], t, [x], ps; name) +end +function Damper(; name, c = 10) + ps = @parameters c=c + @variables vel(t)=0 + ODESystem(Equation[], t, [vel], ps; name) +end +function SpringDamper(; name, k=false, c=false) + spring = Spring(; name=:spring, k) + damper = Damper(; name=:damper, c) + compose( + ODESystem(Equation[], t; name), + spring, damper) +end +connect_sd(sd, m1, m2) = [sd.spring.x ~ m1.pos - m2.pos, sd.damper.vel ~ m1.vel - m2.vel] +sd_force(sd) = -sd.spring.k * sd.spring.x - sd.damper.c * sd.damper.vel +@named mass1 = Mass(; m=1) +@named mass2 = Mass(; m=1) +@named sd = SpringDamper(; k=1000, c=10) +function Model(u, d=0) + eqs = [ + connect_sd(sd, mass1, mass2) + Dₜ(mass1.vel) ~ ( sd_force(sd) + u) / mass1.m + Dₜ(mass2.vel) ~ (-sd_force(sd) + d) / mass2.m + ] + @named _model = ODESystem(eqs, t; observed=[y~mass2.pos]) + @named model = compose(_model, mass1, mass2, sd) +end +model = Model(sin(30t)) +sys = structural_simplify(model) +@test isempty(ModelingToolkit.continuous_events(sys)) \ No newline at end of file