Skip to content

Commit c0578f8

Browse files
committed
Get observed variables
1 parent b0c2295 commit c0578f8

File tree

12 files changed

+46
-17
lines changed

12 files changed

+46
-17
lines changed

docs/src/tutorials/acausal_components.md

+7
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ sol = solve(prob)
320320
plot(sol)
321321
```
322322

323+
By default, this plots only the unknown variables that had to be solved for.
323324
However, what if we wanted to plot the timeseries of a different variable? Do
324325
not worry, that information was not thrown away! Instead, transformations
325326
like `structural_simplify` simply change unknown variables into observables which are
@@ -346,3 +347,9 @@ or we can plot the timeseries of the resistor's voltage:
346347
```@example acausal
347348
plot(sol, idxs = [rc_model.resistor.v])
348349
```
350+
351+
Although it may be more confusing than helpful here, we can of course also plot all unknown and observed variables together:
352+
353+
```@example acausal
354+
plot(sol, idxs = [unknowns(rc_model); observeds(rc_model)])
355+
```

src/ModelingToolkit.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ export Differential, expand_derivatives, @derivatives
297297
export Equation, ConstrainedEquation
298298
export Term, Sym
299299
export SymScope, LocalScope, ParentScope, DelayParentScope, GlobalScope
300-
export independent_variable, equations, controls, observed, full_equations
300+
export independent_variable, equations, controls, observed, observeds, full_equations
301301
export initialization_equations, guesses, defaults, parameter_dependencies, hierarchy
302302
export structural_simplify, expand_connections, linearize, linearization_function,
303303
LinearizationProblem

src/systems/abstractsystem.jl

+25-3
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ function has_observed_with_lhs(sys, sym)
430430
if has_index_cache(sys) && (ic = get_index_cache(sys)) !== nothing
431431
return haskey(ic.observed_syms_to_timeseries, sym)
432432
else
433-
return any(isequal(sym), [eq.lhs for eq in observed(sys)])
433+
return any(isequal(sym), observeds(sys))
434434
end
435435
end
436436

@@ -489,7 +489,7 @@ function _all_ts_idxs!(ts_idxs, ::ScalarSymbolic, sys, sym::Symbol)
489489
if has_index_cache(sys) && (ic = get_index_cache(sys)) !== nothing
490490
return _all_ts_idxs!(ts_idxs, sys, ic.symbol_to_variable[sym])
491491
elseif is_variable(sys, sym) || is_independent_variable(sys, sym) ||
492-
any(isequal(sym), [getname(eq.lhs) for eq in observed(sys)])
492+
any(isequal(sym), getname.(observeds(sys)))
493493
push!(ts_idxs, ContinuousTimeseries())
494494
elseif is_timeseries_parameter(sys, sym)
495495
push!(ts_idxs, timeseries_parameter_index(sys, s).timeseries_idx)
@@ -579,7 +579,7 @@ SymbolicIndexingInterface.constant_structure(::AbstractSystem) = true
579579

580580
function SymbolicIndexingInterface.all_variable_symbols(sys::AbstractSystem)
581581
syms = variable_symbols(sys)
582-
obs = getproperty.(observed(sys), :lhs)
582+
obs = observeds(sys)
583583
return isempty(obs) ? syms : vcat(syms, obs)
584584
end
585585

@@ -1411,6 +1411,7 @@ _nonum(@nospecialize x) = x isa Num ? x.val : x
14111411
$(TYPEDSIGNATURES)
14121412
14131413
Get the unknown variables of the system `sys` and its subsystems.
1414+
These must be explicitly solved for, unlike `observeds(sys)`.
14141415
14151416
See also [`ModelingToolkit.get_unknowns`](@ref).
14161417
"""
@@ -1673,6 +1674,14 @@ function controls(sys::AbstractSystem)
16731674
isempty(systems) ? ctrls : [ctrls; reduce(vcat, namespace_controls.(systems))]
16741675
end
16751676

1677+
"""
1678+
$(TYPEDSIGNATURES)
1679+
1680+
Get the observed equations of the system `sys` and its subsystems.
1681+
These can be expressed in terms of `unknowns(sys)`, and do not have to be explicitly solved for.
1682+
1683+
See also [`observeds`](@ref) and [`ModelingToolkit.get_observed()`](@ref).
1684+
"""
16761685
function observed(sys::AbstractSystem)
16771686
obs = get_observed(sys)
16781687
systems = get_systems(sys)
@@ -1682,6 +1691,19 @@ function observed(sys::AbstractSystem)
16821691
init = Equation[])]
16831692
end
16841693

1694+
"""
1695+
$(TYPEDSIGNATURES)
1696+
1697+
Get the observed variables of the system `sys` and its subsystems.
1698+
These can be expressed in terms of `unknowns(sys)`, and do not have to be explicitly solved for.
1699+
It is equivalent to all left hand sides of `observed(sys)`.
1700+
1701+
See also [`observed`](@ref).
1702+
"""
1703+
function observeds(sys::AbstractSystem)
1704+
return map(eq -> eq.lhs, observed(sys))
1705+
end
1706+
16851707
Base.@deprecate default_u0(x) defaults(x) false
16861708
Base.@deprecate default_p(x) defaults(x) false
16871709

src/systems/diffeqs/abstractodesystem.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ function InitializationProblem{iip, specialize}(sys::AbstractSystem,
14961496
@warn errmsg
14971497
end
14981498

1499-
uninit = setdiff(unknowns(sys), [unknowns(isys); getfield.(observed(isys), :lhs)])
1499+
uninit = setdiff(unknowns(sys), [unknowns(isys); observeds(isys)])
15001500

15011501
# TODO: throw on uninitialized arrays
15021502
filter!(x -> !(x isa Symbolics.Arr), uninit)
@@ -1548,10 +1548,10 @@ function InitializationProblem{iip, specialize}(sys::AbstractSystem,
15481548
symbolic_type(val) == NotSymbolic() || continue
15491549
u0T = promote_type(u0T, typeof(val))
15501550
end
1551-
for eq in observed(isys)
1551+
for sym in observeds(isys)
15521552
# ignore HACK-ed observed equations
1553-
symbolic_type(eq.lhs) == ArraySymbolic() && continue
1554-
val = fixpoint_sub(eq.lhs, fullmap)
1553+
symbolic_type(sym) == ArraySymbolic() && continue
1554+
val = fixpoint_sub(sym, fullmap)
15551555
symbolic_type(val) == NotSymbolic() || continue
15561556
u0T = promote_type(u0T, typeof(val))
15571557
end

src/systems/diffeqs/odesystem.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ function build_explicit_observed_function(sys, ts;
532532

533533
vs = ModelingToolkit.vars(ts; op)
534534
namespace_subs = Dict()
535-
ns_map = Dict{Any, Any}(renamespace(sys, eq.lhs) => eq.lhs for eq in observed(sys))
535+
ns_map = Dict{Any, Any}(renamespace(sys, obs) => obs for obs in observeds(sys))
536536
for sym in unknowns(sys)
537537
ns_map[renamespace(sys, sym)] = sym
538538
if iscall(sym) && operation(sym) === getindex

src/systems/nonlinear/nonlinearsystem.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct NonlinearSystem <: AbstractTimeIndependentSystem
3232
ps::Vector
3333
"""Array variables."""
3434
var_to_name::Any
35-
"""Observed variables."""
35+
"""Observed equations."""
3636
observed::Vector{Equation}
3737
"""
3838
Jacobian matrix. Note: this field will not be defined until

src/systems/optimization/constraints_system.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct ConstraintsSystem <: AbstractTimeIndependentSystem
3333
ps::Vector
3434
"""Array variables."""
3535
var_to_name::Any
36-
"""Observed variables."""
36+
"""Observed equations."""
3737
observed::Vector{Equation}
3838
"""
3939
Jacobian matrix. Note: this field will not be defined until

src/systems/optimization/optimizationsystem.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct OptimizationSystem <: AbstractOptimizationSystem
3131
ps::Vector
3232
"""Array variables."""
3333
var_to_name::Any
34-
"""Observed variables."""
34+
"""Observed equations."""
3535
observed::Vector{Equation}
3636
"""List of constraint equations of the system."""
3737
constraints::Vector{Union{Equation, Inequality}}

src/systems/problem_utils.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ function get_u0_p(sys,
978978
u0map = Dict(u0map)
979979
end
980980
if u0map isa Dict
981-
allobs = Set(getproperty.(observed(sys), :lhs))
981+
allobs = Set(observeds(sys))
982982
if any(in(allobs), keys(u0map))
983983
u0s_in_obs = filter(in(allobs), keys(u0map))
984984
@warn "Observed variables cannot be assigned initial values. Initial values for $u0s_in_obs will be ignored."

src/systems/systemstructure.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ function _structural_simplify!(state::TearingState, io; simplify = false,
721721
sys = ModelingToolkit.tearing(
722722
sys, state; simplify, mm, check_consistency, kwargs...)
723723
end
724-
fullunknowns = [map(eq -> eq.lhs, observed(sys)); unknowns(sys)]
724+
fullunknowns = [observeds(sys); unknowns(sys)]
725725
@set! sys.observed = ModelingToolkit.topsort_equations(observed(sys), fullunknowns)
726726

727727
ModelingToolkit.invalidate_cache!(sys), input_idxs

test/serialization.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ sys = include_string(@__MODULE__, str)
3131

3232
# check answer
3333
ss = structural_simplify(rc_model)
34-
all_obs = [o.lhs for o in observed(ss)]
34+
all_obs = observeds(ss)
3535
prob = ODEProblem(ss, [capacitor.v => 0.0], (0, 0.1))
3636
sol = solve(prob, ImplicitEuler())
3737

test/structural_transformation/utils.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ end
5151
[D(x) ~ z[1] + z[2] + foo(z)[1], y[1] ~ 2t, y[2] ~ 3t, z ~ foo(y)], t)
5252
@test length(equations(sys)) == 1
5353
@test length(observed(sys)) == 7
54-
@test any(eq -> isequal(eq.lhs, y), observed(sys))
55-
@test any(eq -> isequal(eq.lhs, z), observed(sys))
54+
@test any(obs -> isequal(obs, y), observeds(sys))
55+
@test any(obs -> isequal(obs, z), observeds(sys))
5656
prob = ODEProblem(sys, [x => 1.0], (0.0, 1.0), [foo => _tmp_fn])
5757
@test_nowarn prob.f(prob.u0, prob.p, 0.0)
5858

0 commit comments

Comments
 (0)