Skip to content

Commit 4365810

Browse files
committed
Implement continous-time solution comparison by integration measure(ref - sol)
1 parent 38d078b commit 4365810

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/test/continous/delta_sol.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,51 @@ function compare_solutions(
7171
end
7272
export compare_solutions
7373

74+
function compare_dense_solutions(
75+
(ref_name, reference)::Pair{Symbol, <:SciMLBase.AbstractTimeseriesSolution},
76+
sols::Vector{<:Pair{Symbol, <:SciMLBase.AbstractTimeseriesSolution}};
77+
integrator=Tsit5(),
78+
metric=abs
79+
)
80+
results = Dict{Symbol, Any}()
81+
reference_container = symbolic_container(reference)
82+
containers = symbolic_container.(last.(sols))
83+
84+
measured_reference = measured_values(reference_container)
85+
sols_measured = measured_values.(containers)
86+
@assert all(_symbolic_subset.((measured_reference,), sols_measured)) "Test solutions must expose a superset of the reference's variables for comparison"
87+
@assert length(measured_reference) > 0 "Compared solutions must share at least one measured variable"
88+
measured = measured_reference
89+
90+
timebounds(sol) = (sol.t[1], sol.t[end])
91+
@assert reference.dense "Dense (integrated) comparision requires a dense reference solution"
92+
for (test_name, test_sol) in sols
93+
@assert test_sol.dense "Test solution $(test_name) must be dense in order to use continous-time comparison"
94+
@assert timebounds(test_sol) == timebounds(reference) "Test solution $(test_name) has time range $(timebounds(test_sol)) which differs from the reference $(timebounds(reference))"
95+
end
96+
97+
98+
ref_t_vars = independent_variable_symbols(reference_container)
99+
if length(ref_t_vars) > 1
100+
@error "PDE solutions not currently supported; only one iv is allowed"
101+
end
102+
ref_t_var = first(ref_t_vars)
103+
104+
state_size = length(measured)
105+
function compare!(du, u, p, t)
106+
offs = 1
107+
for (test_name, test_sol) in sols
108+
du[offs:offs+state_size-1] .= abs.(reference(t, idxs=measured) .- test_sol(t, idxs=measured))
109+
offs += state_size
110+
end
111+
end
112+
func = ODEFunction(compare!; sys = SymbolCache(collect(Iterators.flatten([namespace_symbol.((test_name, ), measured) for (test_name, _) in sols])), [], ref_t_var))
113+
prob = ODEProblem(func, zeros(length(sols) * length(measured)), timebounds(reference))
114+
soln = solve(prob, integrator)
115+
return soln
116+
end
117+
export compare_dense_solutions
118+
74119
function compute_error_metrics(output_results, ref_soln, test_soln)
75120
delta = ref_soln - test_soln
76121
output_results[:l∞] = maximum(vecvecapply((x) -> abs.(x), delta))

test/timeseries.jl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Base.isapprox((v1, t1)::Tuple{Vector{Float64}, Float64}, (v2, t2)::Tuple{Vector{
22
tol = 1e-8
33

44
@testset "Continous" begin
5-
@testset "Model-Model Comparison" begin
5+
@testset "Model-Model Mixed (self-discretized) Comparison" begin
66
using ModelingToolkit: t_nounits as t, D_nounits as D
77
@variables x(t) [measured=true] y(t) [measured=true]
88
@parameters τ
@@ -35,4 +35,23 @@ tol = 1e-8
3535
@test results[:metrics][:bad][:l2] > tol
3636
@test results[:metrics][:bad][:final] > tol
3737
end
38+
@testset "Model-Model Continous Comparison" begin
39+
using ModelingToolkit: t_nounits as t, D_nounits as D
40+
@variables x(t) [measured=true] y(t) [measured=true]
41+
@parameters τ
42+
@named fol_sys = ODESystem([D(x) ~ (1 - y) / τ; y ~ x], t)
43+
fol = structural_simplify(fol_sys)
44+
prob1 = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 3.0])
45+
sol1 = solve(prob1, Tsit5(), reltol = 1e-8, abstol = 1e-8)
46+
prob2 = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 3.0])
47+
sol2 = solve(prob2, Tsit5(), reltol = 1e-8, abstol = 1e-8)
48+
prob3 = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 1.0])
49+
sol3 = solve(prob3, Tsit5(), reltol = 1e-8, abstol = 1e-8)
50+
51+
results = compare_dense_solutions(:reference=>sol1, [:good=>sol2, :bad=>sol3])
52+
@test results[Symbol("good/x(t)"), end] < tol
53+
@test results[Symbol("good/y(t)"), end] < tol
54+
@test results[Symbol("bad/x(t)"), end] > tol
55+
@test results[Symbol("bad/y(t)"), end] > tol
56+
end
3857
end

0 commit comments

Comments
 (0)