Skip to content

Commit 6d63ffd

Browse files
test: test parameters as initialization unknowns
1 parent 8ec6d3e commit 6d63ffd

File tree

2 files changed

+132
-2
lines changed

2 files changed

+132
-2
lines changed

test/initializationsystem.jl

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ModelingToolkit, OrdinaryDiffEq, NonlinearSolve, Test
2+
using SymbolicIndexingInterface
23
using ModelingToolkit: t_nounits as t, D_nounits as D
34

45
@parameters g
@@ -576,3 +577,132 @@ sol = solve(oprob_2nd_order_2, Rosenbrock23()) # retcode: Success
576577
sol = solve(prob, Tsit5(), reltol = 1e-4)
577578
@test all(sol(1.0, idxs = sys.x) .≈ +exp(1)) && all(sol(1.0, idxs = sys.y) .≈ -exp(1))
578579
end
580+
581+
@testset "Initialization of parameters" begin
582+
function test_parameter(prob, sym, val, initialval = zero(val))
583+
@test prob.ps[sym] initialval
584+
@test init(prob, Tsit5()).ps[sym] val
585+
@test solve(prob, Tsit5()).ps[sym] val
586+
end
587+
function test_initializesystem(sys, u0map, pmap, p, equation)
588+
isys = ModelingToolkit.generate_initializesystem(
589+
sys; u0map, pmap, guesses = ModelingToolkit.guesses(sys))
590+
@test is_variable(isys, p)
591+
@test equation in equations(isys) || (0 ~ -equation.rhs) in equations(isys)
592+
end
593+
@variables x(t) y(t)
594+
@parameters p q
595+
u0map = Dict(x => 1.0, y => 1.0)
596+
pmap = Dict()
597+
pmap[q] = 1.0
598+
# `missing` default, equation from ODEProblem
599+
@mtkbuild sys = ODESystem(
600+
[D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => missing], guesses = [p => 1.0])
601+
pmap[p] = 2q
602+
prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap)
603+
test_parameter(prob, p, 2.0)
604+
# `missing` default, provided guess
605+
@mtkbuild sys = ODESystem(
606+
[D(x) ~ x, p ~ x + y], t; defaults = [p => missing], guesses = [p => 0.0])
607+
prob = ODEProblem(sys, u0map, (0.0, 1.0))
608+
test_parameter(prob, p, 2.0)
609+
test_initializesystem(sys, u0map, pmap, p, 0 ~ p - x - y)
610+
611+
# `missing` to ODEProblem, equation from default
612+
@mtkbuild sys = ODESystem(
613+
[D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 1.0])
614+
pmap[p] = missing
615+
prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap)
616+
test_parameter(prob, p, 2.0)
617+
test_initializesystem(sys, u0map, pmap, p, 0 ~ 2q - p)
618+
test_parameter(prob2, p, 2.0)
619+
# `missing` to ODEProblem, provided guess
620+
@mtkbuild sys = ODESystem(
621+
[D(x) ~ x, p ~ x + y], t; guesses = [p => 0.0])
622+
prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap)
623+
test_parameter(prob, p, 2.0)
624+
test_initializesystem(sys, u0map, pmap, p, 0 ~ x + y - p)
625+
626+
# No `missing`, default and guess
627+
@mtkbuild sys = ODESystem(
628+
[D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 0.0])
629+
delete!(pmap, p)
630+
prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap)
631+
test_parameter(prob, p, 2.0)
632+
test_initializesystem(sys, u0map, pmap, p, 0 ~ 2q - p)
633+
634+
# Should not be solved for:
635+
636+
# ODEProblem value with guess, no `missing`
637+
@mtkbuild sys = ODESystem([D(x) ~ x * q, D(y) ~ y * p], t; guesses = [p => 0.0])
638+
_pmap = merge(pmap, Dict(p => 3q))
639+
prob = ODEProblem(sys, u0map, (0.0, 1.0), _pmap)
640+
@test prob.ps[p] 3.0
641+
@test prob.f.initializeprob === nothing
642+
# Default overridden by ODEProblem, guess provided
643+
@mtkbuild sys = ODESystem(
644+
[D(x) ~ q * x, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 1.0])
645+
prob = ODEProblem(sys, u0map, (0.0, 1.0), _pmap)
646+
@test prob.ps[p] 3.0
647+
@test prob.f.initializeprob === nothing
648+
649+
@mtkbuild sys = ODESystem([D(x) ~ x, p ~ x + y], t; guesses = [p => 0.0])
650+
@test_throws ModelingToolkit.MissingParametersError ODEProblem(
651+
sys, [x => 1.0, y => 1.0], (0.0, 1.0))
652+
653+
@testset "Null system" begin
654+
@variables x(t) y(t) s(t)
655+
@parameters x0 y0
656+
@mtkbuild sys = ODESystem([x ~ x0, y ~ y0, s ~ x + y], t; guesses = [y0 => 0.0])
657+
prob = ODEProblem(sys, [s => 1.0], (0.0, 1.0), [x0 => 0.3, y0 => missing])
658+
test_parameter(prob, y0, 0.7)
659+
end
660+
661+
using ModelingToolkitStandardLibrary.Mechanical.TranslationalModelica: Fixed, Mass,
662+
Spring, Force,
663+
Damper
664+
using ModelingToolkitStandardLibrary.Mechanical: TranslationalModelica as TM
665+
using ModelingToolkitStandardLibrary.Blocks: Constant
666+
667+
@named mass = TM.Mass(; m = 1.0, s = 1.0, v = 0.0, a = 0.0)
668+
@named fixed = Fixed(; s0 = 0.0)
669+
@named spring = Spring(; c = 2.0, s_rel0 = nothing)
670+
@named gravity = Force()
671+
@named constant = Constant(; k = 9.81)
672+
@named damper = TM.Damper(; d = 0.1)
673+
@mtkbuild sys = ODESystem(
674+
[connect(fixed.flange, spring.flange_a), connect(spring.flange_b, mass.flange_a),
675+
connect(mass.flange_a, gravity.flange), connect(constant.output, gravity.f),
676+
connect(fixed.flange, damper.flange_a), connect(damper.flange_b, mass.flange_a)],
677+
t;
678+
systems = [fixed, spring, mass, gravity, constant, damper],
679+
guesses = [spring.s_rel0 => 1.0])
680+
prob = ODEProblem(sys, [], (0.0, 1.0), [spring.s_rel0 => missing])
681+
test_parameter(prob, spring.s_rel0, -3.905)
682+
end
683+
684+
@testset "Update initializeprob parameters" begin
685+
@variables x(t) y(t)
686+
@parameters p q
687+
@mtkbuild sys = ODESystem(
688+
[D(x) ~ x, p ~ x + y], t; guesses = [x => 0.0, p => 0.0])
689+
prob = ODEProblem(sys, [y => 1.0], (0.0, 1.0), [p => 3.0])
690+
@test prob.f.initializeprob.ps[p] 3.0
691+
@test init(prob, Tsit5())[x] 2.0
692+
prob.ps[p] = 2.0
693+
@test prob.f.initializeprob.ps[p] 3.0
694+
@test init(prob, Tsit5())[x] 1.0
695+
ModelingToolkit.defaults(prob.f.sys)[p] = missing
696+
end
697+
698+
@testset "Equations for dependent parameters" begin
699+
@variables x(t)
700+
@parameters p q=5 r
701+
@mtkbuild sys = ODESystem(
702+
D(x) ~ 2x + r, t; parameter_dependencies = [r ~ p + 2q, q ~ p + 3],
703+
guesses = [p => 1.0])
704+
prob = ODEProblem(sys, [x => 1.0], (0.0, 1.0), [p => missing])
705+
@test length(equations(ModelingToolkit.get_parent(prob.f.initializeprob.f.sys))) == 4
706+
integ = init(prob, Tsit5())
707+
@test integ.ps[p] 2
708+
end

test/parameter_dependencies.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ using SymbolicIndexingInterface
1010
using NonlinearSolve
1111

1212
@testset "ODESystem with callbacks" begin
13-
@parameters p1=1.0 p2=1.0
13+
@parameters p1=1.0 p2
1414
@variables x(t)
1515
cb1 = [x ~ 2.0] => [p1 ~ 2.0] # triggers at t=-2+√6
1616
function affect1!(integ, u, p, ctx)
@@ -31,7 +31,7 @@ using NonlinearSolve
3131
prob = ODEProblem(sys, [x => 1.0], (0.0, 1.5), jac = true)
3232
@test prob.ps[p1] == 1.0
3333
@test prob.ps[p2] == 2.0
34-
@test_nowarn solve(prob, Tsit5())
34+
@test SciMLBase.successful_retcode(solve(prob, Tsit5()))
3535
prob = ODEProblem(sys, [x => 1.0], (0.0, 1.5), [p1 => 1.0], jac = true)
3636
@test prob.ps[p1] == 1.0
3737
@test prob.ps[p2] == 2.0

0 commit comments

Comments
 (0)