Skip to content

Commit 0641937

Browse files
committed
add tests
1 parent 1d872e0 commit 0641937

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

test/accessor_functions.jl

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
### Preparations ###
2+
3+
# Fetch packages.
4+
using ModelingToolkit, Test
5+
using ModelingToolkit: t_nounits as t, D_nounits as D
6+
import ModelingToolkit: get_ps, get_unknowns, get_observed, get_eqs, get_continuous_events,
7+
get_discrete_events, namespace_equations
8+
9+
# Creates helper functions.
10+
function all_sets_equal(args...)
11+
for arg in args[2:end]
12+
issetequal(args[1], arg) || return false
13+
end
14+
return true
15+
end
16+
function sym_issubset(set1, set2)
17+
for sym1 in set1
18+
any(isequal(sym1, sym2) for sym2 in set2) || return false
19+
end
20+
return true
21+
end
22+
23+
### Basic Tests ###
24+
25+
# Checks `toplevel = false` argument for various accessors (currently only for `ODESystem`s).
26+
# Compares to `toplevel = true` version, and `get_` functions.
27+
# Checks accessors for parameters, unknowns, equations, observables, and events.
28+
let
29+
# Prepares model components.
30+
@parameters p_top p_mid1 p_mid2 p_bot d
31+
@variables X_top(t) X_mid1(t) X_mid2(t) X_bot(t) Y(t) O(t)
32+
33+
# Creates the systems (individual and hierarchical).
34+
eqs_top = [
35+
D(X_top) ~ p_top - d*X_top,
36+
D(Y) ~ log(X_top) - Y^2 + 3.0,
37+
O ~ (p_top + d)*X_top + Y
38+
]
39+
eqs_mid1 = [
40+
D(X_mid1) ~ p_mid1 - d*X_mid1^2,
41+
D(Y) ~ D(X_mid1) - Y^3,
42+
O ~ (p_mid1 + d)*X_mid1 + Y
43+
]
44+
eqs_mid2 = [
45+
D(X_mid2) ~ p_mid2 - d*X_mid2,
46+
X_mid2^3 ~ log(X_mid2 + Y) - Y^2 + 3.0,
47+
O ~ (p_mid2 + d)*X_mid2 + Y
48+
]
49+
eqs_bot = [
50+
D(X_bot) ~ p_bot - d*X_bot,
51+
D(Y) ~ -Y^3,
52+
O ~ (p_bot + d)*X_bot + Y
53+
]
54+
cevs = [[t ~ 1.0] => [Y ~ Y + 2.0]]
55+
devs = [(t == 2.0) => [Y ~ Y + 2.0]]
56+
@named sys_bot = ODESystem(eqs_bot, t; systems = [], continuous_events = cevs, discrete_events = devs)
57+
@named sys_mid2 = ODESystem(eqs_mid2, t; systems = [], continuous_events = cevs, discrete_events = devs)
58+
@named sys_mid1 = ODESystem(eqs_mid1, t; systems = [sys_bot], continuous_events = cevs, discrete_events = devs)
59+
@named sys_top = ODESystem(eqs_top, t; systems = [sys_mid1, sys_mid2], continuous_events = cevs, discrete_events = devs)
60+
sys_bot_comp = complete(sys_bot)
61+
sys_mid2_comp = complete(sys_mid2)
62+
sys_mid1_comp = complete(sys_mid1)
63+
sys_top_comp = complete(sys_top)
64+
sys_bot_ss = structural_simplify(sys_bot)
65+
sys_mid2_ss = structural_simplify(sys_mid2)
66+
sys_mid1_ss = structural_simplify(sys_mid1)
67+
sys_top_ss = structural_simplify(sys_top)
68+
69+
# Checks `parameters` for `toplevel = false`.
70+
@test all_sets_equal(parameters.([sys_bot, sys_bot_comp, sys_bot_ss])..., [d, p_bot])
71+
@test all_sets_equal(parameters.([sys_mid1, sys_mid1_comp, sys_mid1_ss])..., [d, p_mid1, sys_bot.d, sys_bot.p_bot])
72+
@test all_sets_equal(parameters.([sys_mid2, sys_mid2_comp, sys_mid2_ss])..., [d, p_mid2])
73+
@test all_sets_equal(parameters.([sys_top, sys_top_comp, sys_top_ss])..., [d, p_top, sys_mid1.d, sys_mid1.p_mid1, sys_mid1.sys_bot.d, sys_mid1.sys_bot.p_bot, sys_mid2.d, sys_mid2.p_mid2])
74+
75+
# Checks `parameters`` for `toplevel = true`. Compares to known parameters and also checks that
76+
# these are subset of what `get_ps` returns.
77+
@test all_sets_equal(parameters.([sys_bot, sys_bot_comp, sys_bot_ss]; toplevel = true)..., [d, p_bot])
78+
@test_broken all_sets_equal(parameters.([sys_mid1, sys_mid1_comp, sys_mid1_ss]; toplevel = true)..., [d, p_mid1])
79+
@test all_sets_equal(parameters.([sys_mid2, sys_mid2_comp, sys_mid2_ss]; toplevel = true)..., [d, p_mid2])
80+
@test_broken all_sets_equal(parameters.([sys_top, sys_top_comp, sys_top_ss]; toplevel = true)..., [d, p_top])
81+
@test all(sym_issubset(parameters(sys; toplevel = true), get_ps(sys)) for sys in [sys_bot, sys_mid2, sys_mid1, sys_top])
82+
83+
# Checks `unknowns` for `toplevel = false`. O(t) is eliminated by `structural_simplify` and
84+
# must be considered separately.
85+
@test all_sets_equal(unknowns.([sys_bot, sys_bot_comp])..., [O, Y, X_bot])
86+
@test all_sets_equal(unknowns.([sys_bot_ss])..., [Y, X_bot])
87+
@test all_sets_equal(unknowns.([sys_mid1, sys_mid1_comp])..., [O, Y, X_mid1, sys_bot.Y, sys_bot.O, sys_bot.X_bot])
88+
@test all_sets_equal(unknowns.([sys_mid1_ss])..., [Y, X_mid1, sys_bot.Y, sys_bot.X_bot])
89+
@test all_sets_equal(unknowns.([sys_mid2, sys_mid2_comp])..., [O, Y, X_mid2])
90+
@test all_sets_equal(unknowns.([sys_mid2_ss])..., [Y, X_mid2])
91+
@test all_sets_equal(unknowns.([sys_top, sys_top_comp])..., [O, Y, X_top, sys_mid1.O, sys_mid1.Y, sys_mid1.X_mid1, sys_mid1.sys_bot.O, sys_mid1.sys_bot.Y, sys_mid1.sys_bot.X_bot, sys_mid2.O, sys_mid2.Y, sys_mid2.X_mid2])
92+
@test all_sets_equal(unknowns.([sys_top_ss])..., [Y, X_top, sys_mid1.Y, sys_mid1.X_mid1, sys_mid1.sys_bot.Y, sys_mid1.sys_bot.X_bot, sys_mid2.Y, sys_mid2.X_mid2])
93+
94+
# Checks `unknowns` for `toplevel = true`. Note that O is not eliminated here (as we go back
95+
# to original parent system). Also checks that outputs are subsets of what `get_ps` returns..
96+
@test all_sets_equal(unknowns.([sys_bot, sys_bot_comp, sys_bot_ss]; toplevel = true)..., [O, Y, X_bot])
97+
@test all_sets_equal(unknowns.([sys_mid1, sys_mid1_comp]; toplevel = true)..., [O, Y, X_mid1])
98+
@test all_sets_equal(unknowns.([sys_mid2, sys_mid2_comp]; toplevel = true)..., [O, Y, X_mid2])
99+
@test all_sets_equal(unknowns.([sys_top, sys_top_comp]; toplevel = true)..., [O, Y, X_top])
100+
@test all(sym_issubset(unknowns(sys; toplevel = true), get_unknowns(sys)) for sys in [sys_bot, sys_mid1, sys_mid2, sys_top])
101+
102+
# Checks `equations` for `toplevel = false`. Do not check ss equations as these might potentially
103+
# be structurally simplified to new equations.
104+
@test all_sets_equal(equations.([sys_bot, sys_bot_comp])..., eqs_bot)
105+
@test all_sets_equal(equations.([sys_mid1, sys_mid1_comp])..., [eqs_mid1; namespace_equations(sys_bot)])
106+
@test all_sets_equal(equations.([sys_mid2, sys_mid2_comp])..., eqs_mid2)
107+
@test all_sets_equal(equations.([sys_top, sys_top_comp])..., [eqs_top; namespace_equations(sys_mid1); namespace_equations(sys_mid2)])
108+
109+
# Checks `equations` for `toplevel = true`. Do not check ss equations directly as these
110+
# might potentially be structurally simplified to new equations.
111+
@test all_sets_equal(equations.([sys_bot, sys_bot_comp]; toplevel = true)..., eqs_bot)
112+
@test all_sets_equal(equations.([sys_mid1, sys_mid1_comp]; toplevel = true)..., eqs_mid1)
113+
@test all_sets_equal(equations.([sys_mid2, sys_mid2_comp]; toplevel = true)..., eqs_mid2)
114+
@test all_sets_equal(equations.([sys_top, sys_top_comp]; toplevel = true)..., eqs_top)
115+
@test all(sym_issubset(equations(sys; toplevel = true), get_eqs(sys)) for sys in [sys_bot, sys_mid2, sys_mid1, sys_top])
116+
117+
# Checks `observed for `toplevel = false`. For non-ss systems, there are no observables.
118+
@test all_sets_equal(observed.([sys_bot, sys_bot_comp, sys_mid1, sys_mid1_comp, sys_mid2, sys_mid2_comp, sys_top, sys_top_comp])..., [])
119+
@test issetequal(observed(sys_bot_ss), eqs_bot[3:3])
120+
@test issetequal(observed(sys_mid1_ss), [eqs_mid1[3:3]; namespace_equations(sys_bot)[3:3]])
121+
@test issetequal(observed(sys_mid2_ss), eqs_mid2[3:3])
122+
@test issetequal(observed(sys_top_ss), [eqs_top[3:3]; namespace_equations(sys_mid1)[3:3:6]; namespace_equations(sys_mid2)[3:3]])
123+
124+
# Checks `observed` for `toplevel = true`. Again, for non-ss systems, there are no observables.
125+
# Also checks that `toplevel = true` yields subset of `get_observed`.
126+
@test all_sets_equal(observed.([sys_bot, sys_bot_comp, sys_mid1, sys_mid1_comp, sys_mid2, sys_mid2_comp, sys_top, sys_top_comp]; toplevel = true)..., [])
127+
@test_broken issetequal(observed(sys_bot_ss; toplevel = true), eqs_bot[3:3])
128+
@test_broken issetequal(observed(sys_mid1_ss; toplevel = true), eqs_mid1[3:3])
129+
@test_broken issetequal(observed(sys_mid2_ss; toplevel = true), eqs_mid2[3:3])
130+
@test_broken issetequal(observed(sys_top_ss; toplevel = true), eqs_top[3:3])
131+
@test all(sym_issubset(observed(sys; toplevel = true), get_observed(sys)) for sys in [sys_bot, sys_mid2, sys_mid1, sys_top])
132+
133+
# Checks `continuous_events` and `discrete_events` for `toplevel = true` (more straightforward
134+
# as I stored the same singe event in all systems). Don't check for `toplevel = false` as
135+
# technically not needed for these tests and name spacing the events is a mess.
136+
mtk_cev = ModelingToolkit.SymbolicContinuousCallback.(cevs)[1]
137+
mtk_dev = ModelingToolkit.SymbolicDiscreteCallback.(devs)[1]
138+
@test all_sets_equal(continuous_events.([sys_bot, sys_bot_comp, sys_bot_ss, sys_mid1, sys_mid1_comp, sys_mid1_ss, sys_mid2, sys_mid2_comp, sys_mid2_ss, sys_top, sys_top_comp, sys_top_ss]; toplevel = true)..., [mtk_cev])
139+
@test all_sets_equal(discrete_events.([sys_bot, sys_bot_comp, sys_bot_ss, sys_mid1, sys_mid1_comp, sys_mid1_ss, sys_mid2, sys_mid2_comp, sys_mid2_ss, sys_top, sys_top_comp, sys_top_ss]; toplevel = true)..., [mtk_dev])
140+
@test all(sym_issubset(continuous_events(sys; toplevel = true), get_continuous_events(sys)) for sys in [sys_bot, sys_mid2, sys_mid1, sys_top])
141+
@test all(sym_issubset(discrete_events(sys; toplevel = true), get_discrete_events(sys)) for sys in [sys_bot, sys_mid2, sys_mid1, sys_top])
142+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ end
6161
@safetestset "Constants Test" include("constants.jl")
6262
@safetestset "Parameter Dependency Test" include("parameter_dependencies.jl")
6363
@safetestset "Equation Type Accessors Test" include("equation_type_accessors.jl")
64+
@safetestset "System Accessor Functions Test" include("accessor_functions.jl")
6465
@safetestset "Equations with complex values" include("complex.jl")
6566
end
6667
end

0 commit comments

Comments
 (0)