Skip to content

Commit 89fdee8

Browse files
authored
New abstract time dependent/independent types & independent_variables method (#1091)
1 parent fc34034 commit 89fdee8

28 files changed

+174
-91
lines changed

docs/src/basics/AbstractSystem.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ It establishes a common set of functionality that is used between systems
77
from ODEs and chemical reactions, allowing users to have a common framework for
88
model manipulation and compilation.
99

10+
### Subtypes
11+
12+
There are three immediate subtypes of `AbstractSystem`, classified by how many independent variables each type has:
13+
* `AbstractTimeIndependentSystem`: has no independent variable (eg: `NonlinearSystem`)
14+
* `AbstractTimeDependentSystem`: has a single independent variable (eg: `ODESystem`)
15+
* `AbstractMultivariateSystem`: may have multiple independent variables (eg: `PDESystem`)
16+
1017
## Constructors and Naming
1118

1219
The `AbstractSystem` interface has a consistent method for constructing systems.
@@ -50,12 +57,11 @@ Optionally, a system could have:
5057
- `observed(sys)`: All observed equations of the system and its subsystems.
5158
- `get_observed(sys)`: Observed equations of the current-level system.
5259
- `get_defaults(sys)`: A `Dict` that maps variables into their default values.
53-
- `independent_variable(sys)`: The independent variable of a system.
60+
- `independent_variables(sys)`: The independent variables of a system.
5461
- `get_noiseeqs(sys)`: Noise equations of the current-level system.
5562

56-
Note that there's `get_iv(sys)`, but it is not advised to use, since it errors
57-
when the system has no field `iv`. `independent_variable(sys)` returns `nothing`
58-
for `NonlinearSystem`s.
63+
Note that if you know a system is an `AbstractTimeDependentSystem` you could use `get_iv` to get the
64+
unique independent variable directly, rather than using `independenent_variables(sys)[1]`, which is clunky and may cause problems if `sys` is an `AbstractMultivariateSystem` because there may be more than one independent variable. `AbstractTimeIndependentSystem`s do not have a method `get_iv`, and `independent_variables(sys)` will return a size-zero result for such. For an `AbstractMultivariateSystem`, `get_ivs` is equivalent.
5965

6066
A system could also have caches:
6167

docs/src/systems/JumpSystem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ JumpSystem
1111
- `get_eqs(sys)` or `equations(sys)`: The equations that define the jump system.
1212
- `get_states(sys)` or `states(sys)`: The set of states in the jump system.
1313
- `get_ps(sys)` or `parameters(sys)`: The parameters of the jump system.
14-
- `independent_variable(sys)`: The independent variable of the jump system.
14+
- `get_iv(sys)`: The independent variable of the jump system.
1515

1616
## Transformations
1717

docs/src/systems/ODESystem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ ODESystem
1111
- `get_eqs(sys)` or `equations(sys)`: The equations that define the ODE.
1212
- `get_states(sys)` or `states(sys)`: The set of states in the ODE.
1313
- `get_ps(sys)` or `parameters(sys)`: The parameters of the ODE.
14-
- `independent_variable(sys)`: The independent variable of the ODE.
14+
- `get_iv(sys)`: The independent variable of the ODE.
1515

1616
## Transformations
1717

docs/src/systems/ReactionSystem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ ReactionSystem
4949
- `get_eqs(sys)` or `equations(sys)`: The reactions that define the system.
5050
- `get_states(sys)` or `states(sys)`: The set of chemical species in the system.
5151
- `get_ps(sys)` or `parameters(sys)`: The parameters of the system.
52-
- `independent_variable(sys)`: The independent variable of the
52+
- `get_iv(sys)`: The independent variable of the
5353
reaction system, usually time.
5454

5555
## Query Functions

docs/src/systems/SDESystem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ sde = SDESystem(ode, noiseeqs)
1717
- `get_eqs(sys)` or `equations(sys)`: The equations that define the SDE.
1818
- `get_states(sys)` or `states(sys)`: The set of states in the SDE.
1919
- `get_ps(sys)` or `parameters(sys)`: The parameters of the SDE.
20-
- `independent_variable(sys)`: The independent variable of the SDE.
20+
- `get_iv(sys)`: The independent variable of the SDE.
2121

2222
## Transformations
2323

src/ModelingToolkit.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ $(TYPEDEF)
7777
TODO
7878
"""
7979
abstract type AbstractSystem end
80-
abstract type AbstractODESystem <: AbstractSystem end
80+
abstract type AbstractTimeDependentSystem <: AbstractSystem end
81+
abstract type AbstractTimeIndependentSystem <: AbstractSystem end
82+
abstract type AbstractODESystem <: AbstractTimeDependentSystem end
83+
abstract type AbstractMultivariateSystem <: AbstractSystem end
8184

8285
"""
8386
$(TYPEDSIGNATURES)
@@ -86,6 +89,8 @@ Get the set of independent variables for the given system.
8689
"""
8790
function independent_variables end
8891

92+
function independent_variable end
93+
8994
"""
9095
$(TYPEDSIGNATURES)
9196
@@ -148,6 +153,7 @@ end
148153

149154
struct Flow end
150155

156+
export AbstractTimeDependentSystem, AbstractTimeIndependentSystem, AbstractMultivariateSystem
151157
export ODESystem, ODEFunction, ODEFunctionExpr, ODEProblemExpr, convert_system
152158
export DAEFunctionExpr, DAEProblemExpr
153159
export SDESystem, SDEFunction, SDEFunctionExpr, SDESystemExpr
@@ -170,7 +176,7 @@ export Differential, expand_derivatives, @derivatives
170176
export Equation, ConstrainedEquation
171177
export Term, Sym
172178
export SymScope, LocalScope, ParentScope, GlobalScope
173-
export independent_variable, states, parameters, equations, controls, observed, structure
179+
export independent_variables, independent_variable, states, parameters, equations, controls, observed, structure
174180
export structural_simplify
175181
export DiscreteSystem, DiscreteProblem
176182

src/structural_transformation/StructuralTransformations.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ using SymbolicUtils.Rewriters
1313
using SymbolicUtils: similarterm, istree
1414

1515
using ModelingToolkit
16-
using ModelingToolkit: ODESystem, AbstractSystem, var_from_nested_derivative,
17-
Differential, states, equations, vars, Symbolic,
18-
diff2term, value, operation, arguments, Sym, Term,
19-
simplify, solve_for, isdiffeq, isdifferential,
16+
using ModelingToolkit: ODESystem, AbstractSystem,var_from_nested_derivative, Differential,
17+
states, equations, vars, Symbolic, diff2term, value,
18+
operation, arguments, Sym, Term, simplify, solve_for,
19+
isdiffeq, isdifferential, get_structure, get_iv, independent_variables,
2020
get_structure, defaults, InvalidSystemException,
2121
ExtraEquationsSystemException,
2222
ExtraVariablesSystemException

src/structural_transformation/codegen.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ function build_torn_function(
208208
out
209209
DestructuredArgs(states, inbounds=!checkbounds)
210210
DestructuredArgs(parameters(sys), inbounds=!checkbounds)
211-
independent_variable(sys)
211+
independent_variables(sys)
212212
],
213213
[],
214214
Let(
@@ -312,7 +312,7 @@ function build_observed_function(
312312
[
313313
DestructuredArgs(diffvars, inbounds=!checkbounds)
314314
DestructuredArgs(parameters(sys), inbounds=!checkbounds)
315-
independent_variable(sys)
315+
independent_variables(sys)
316316
],
317317
[],
318318
Let(

src/structural_transformation/pantelides.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
### Reassemble: structural information -> system
33
###
44

5-
function pantelides_reassemble(sys, eqassoc, assign)
5+
function pantelides_reassemble(sys::ODESystem, eqassoc, assign)
66
s = structure(sys)
77
@unpack fullvars, varassoc = s
88
# Step 1: write derivative equations
@@ -15,7 +15,7 @@ function pantelides_reassemble(sys, eqassoc, assign)
1515
fill!(out_vars, nothing)
1616
out_vars[1:length(fullvars)] .= fullvars
1717

18-
D = Differential(independent_variable(sys))
18+
D = Differential(get_iv(sys))
1919

2020
for (i, v) in enumerate(varassoc)
2121
# fullvars[v] = D(fullvars[i])
@@ -75,11 +75,11 @@ end
7575
7676
Perform Pantelides algorithm.
7777
"""
78-
function pantelides!(sys; maxiters = 8000)
78+
function pantelides!(sys::ODESystem; maxiters = 8000)
7979
s = structure(sys)
8080
# D(j) = assoc[j]
8181
@unpack graph, fullvars, varassoc = s
82-
iv = independent_variable(sys)
82+
iv = get_iv(sys)
8383
neqs = nsrcs(graph)
8484
nvars = length(varassoc)
8585
vcolor = falses(nvars)

src/systems/abstractsystem.jl

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
```julia
3-
calculate_tgrad(sys::AbstractSystem)
3+
calculate_tgrad(sys::AbstractTimeDependentSystem)
44
```
55
66
Calculate the time gradient of a system.
@@ -72,7 +72,7 @@ function calculate_hessian end
7272

7373
"""
7474
```julia
75-
generate_tgrad(sys::AbstractSystem, dvs = states(sys), ps = parameters(sys), expression = Val{true}; kwargs...)
75+
generate_tgrad(sys::AbstractTimeDependentSystem, dvs = states(sys), ps = parameters(sys), expression = Val{true}; kwargs...)
7676
```
7777
7878
Generates a function for the time gradient of a system. Extra arguments control
@@ -138,8 +138,28 @@ function getname(t)
138138
nameof(t)
139139
end
140140
end
141+
#Deprecated
142+
function independent_variable(sys::AbstractSystem)
143+
Base.depwarn("`independent_variable` is deprecated. Use `get_iv` or `independent_variables` instead.",:independent_variable)
144+
isdefined(sys, :iv) ? getfield(sys, :iv) : nothing
145+
end
141146

142-
independent_variable(sys::AbstractSystem) = isdefined(sys, :iv) ? getfield(sys, :iv) : nothing
147+
#Treat the result as a vector of symbols always
148+
function independent_variables(sys::AbstractSystem)
149+
systype = typeof(sys)
150+
@warn "Please declare ($systype) as a subtype of `AbstractTimeDependentSystem`, `AbstractTimeIndependentSystem` or `AbstractMultivariateSystem`."
151+
if isdefined(sys, :iv)
152+
return [getfield(sys, :iv)]
153+
elseif isdefined(sys, :ivs)
154+
return getfield(sys,:ivs)
155+
else
156+
return []
157+
end
158+
end
159+
160+
independent_variables(sys::AbstractTimeDependentSystem) = [getfield(sys, :iv)]
161+
independent_variables(sys::AbstractTimeIndependentSystem) = []
162+
independent_variables(sys::AbstractMultivariateSystem) = getfield(sys, :ivs)
143163

144164
function structure(sys::AbstractSystem)
145165
s = get_structure(sys)
@@ -333,35 +353,35 @@ namespace_controls(sys::AbstractSystem) = controls(sys, controls(sys))
333353

334354
function namespace_defaults(sys)
335355
defs = defaults(sys)
336-
Dict((isparameter(k) ? parameters(sys, k) : states(sys, k)) => namespace_expr(defs[k], nameof(sys), independent_variable(sys)) for k in keys(defs))
356+
Dict((isparameter(k) ? parameters(sys, k) : states(sys, k)) => namespace_expr(defs[k], nameof(sys), independent_variables(sys)) for k in keys(defs))
337357
end
338358

339359
function namespace_equations(sys::AbstractSystem)
340360
eqs = equations(sys)
341361
isempty(eqs) && return Equation[]
342-
iv = independent_variable(sys)
343-
map(eq->namespace_equation(eq,nameof(sys),iv), eqs)
362+
ivs = independent_variables(sys)
363+
map(eq -> namespace_equation(eq, nameof(sys), ivs), eqs)
344364
end
345365

346-
function namespace_equation(eq::Equation,name,iv)
347-
_lhs = namespace_expr(eq.lhs,name,iv)
348-
_rhs = namespace_expr(eq.rhs,name,iv)
366+
function namespace_equation(eq::Equation, name, ivs)
367+
_lhs = namespace_expr(eq.lhs, name, ivs)
368+
_rhs = namespace_expr(eq.rhs, name, ivs)
349369
_lhs ~ _rhs
350370
end
351371

352-
function namespace_expr(O::Sym,name,iv)
353-
isequal(O, iv) ? O : renamespace(name,O)
372+
function namespace_expr(O::Sym, name, ivs)
373+
any(isequal(O), ivs) ? O : renamespace(name, O)
354374
end
355375

356376
_symparam(s::Symbolic{T}) where {T} = T
357-
function namespace_expr(O,name,iv) where {T}
377+
function namespace_expr(O, name, ivs) where {T}
358378
O = value(O)
359379
if istree(O)
360-
renamed = map(a->namespace_expr(a,name,iv), arguments(O))
380+
renamed = map(a -> namespace_expr(a, name, ivs), arguments(O))
361381
if operation(O) isa Sym
362382
renamespace(name, O)
363383
else
364-
similarterm(O,operation(O),renamed)
384+
similarterm(O, operation(O), renamed)
365385
end
366386
else
367387
O
@@ -389,13 +409,13 @@ function controls(sys::AbstractSystem)
389409
end
390410

391411
function observed(sys::AbstractSystem)
392-
iv = independent_variable(sys)
412+
ivs = independent_variables(sys)
393413
obs = get_observed(sys)
394414
systems = get_systems(sys)
395415
[obs;
396416
reduce(vcat,
397-
(map(o->namespace_equation(o, nameof(s), iv), observed(s)) for s in systems),
398-
init=Equation[])]
417+
(map(o -> namespace_equation.(o, nameof(s), ivs), observed(s)) for s in systems),
418+
init = Equation[])]
399419
end
400420

401421
Base.@deprecate default_u0(x) defaults(x) false
@@ -514,9 +534,10 @@ function toexpr(sys::AbstractSystem)
514534
stmt = expr.args
515535

516536
name = Meta.quot(nameof(sys))
517-
iv = independent_variable(sys)
537+
ivs = independent_variables(sys)
518538
ivname = gensym(:iv)
519-
if iv !== nothing
539+
for iv in ivs
540+
ivname = gensym(:iv)
520541
push!(stmt, :($ivname = (@variables $(getname(iv)))[1]))
521542
end
522543

@@ -536,9 +557,12 @@ function toexpr(sys::AbstractSystem)
536557
defs_name = push_defaults!(stmt, defaults(sys), var2name)
537558

538559
if sys isa ODESystem
539-
push!(stmt, :($ODESystem($eqs_name, $ivname, $stsname, $psname; defaults=$defs_name, name=$name)))
560+
iv = get_iv(sys)
561+
ivname = gensym(:iv)
562+
push!(stmt, :($ivname = (@variables $(getname(iv)))[1]))
563+
push!(stmt, :($ODESystem($eqs_name, $ivname, $stsname, $psname; defaults = $defs_name, name=$name)))
540564
elseif sys isa NonlinearSystem
541-
push!(stmt, :($NonlinearSystem($eqs_name, $stsname, $psname; defaults=$defs_name, name=$name)))
565+
push!(stmt, :($NonlinearSystem($eqs_name, $stsname, $psname; defaults = $defs_name, name=$name)))
542566
end
543567

544568
striplines(expr) # keeping the line numbers is never helpful
@@ -891,7 +915,7 @@ function Base.hash(sys::AbstractSystem, s::UInt)
891915
s = foldr(hash, get_ps(sys), init=s)
892916
s = foldr(hash, get_eqs(sys), init=s)
893917
s = foldr(hash, get_observed(sys), init=s)
894-
s = hash(independent_variable(sys), s)
918+
s = hash(independent_variables(sys), s)
895919
return s
896920
end
897921

@@ -903,11 +927,13 @@ by default.
903927
"""
904928
function extend(sys::AbstractSystem, basesys::AbstractSystem; name::Symbol=nameof(sys))
905929
T = SciMLBase.parameterless_type(basesys)
906-
iv = independent_variable(basesys)
907-
if iv === nothing
930+
ivs = independent_variables(basesys)
931+
if length(ivs) == 0
908932
sys = convert_system(T, sys)
933+
elseif length(ivs) == 1
934+
sys = convert_system(T, sys, ivs[1])
909935
else
910-
sys = convert_system(T, sys, iv)
936+
throw("Extending multivariate systems is not supported")
911937
end
912938

913939
eqs = union(equations(basesys), equations(sys))
@@ -917,10 +943,10 @@ function extend(sys::AbstractSystem, basesys::AbstractSystem; name::Symbol=nameo
917943
defs = merge(defaults(basesys), defaults(sys)) # prefer `sys`
918944
syss = union(get_systems(basesys), get_systems(sys))
919945

920-
if iv === nothing
921-
T(eqs, sts, ps, observed=obs, defaults=defs, name=name, systems=syss)
922-
else
923-
T(eqs, iv, sts, ps, observed=obs, defaults=defs, name=name, systems=syss)
946+
if length(ivs) == 0
947+
T(eqs, sts, ps, observed = obs, defaults = defs, name=name, systems = syss)
948+
elseif length(ivs) == 1
949+
T(eqs, ivs[1], sts, ps, observed = obs, defaults = defs, name = name, systems = syss)
924950
end
925951
end
926952

src/systems/control/controlsystem.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract type AbstractControlSystem <: AbstractSystem end
1+
abstract type AbstractControlSystem <: AbstractTimeDependentSystem end
22

33
function namespace_controls(sys::AbstractControlSystem)
44
[rename(x,renamespace(nameof(sys),nameof(x))) for x in controls(sys)]

0 commit comments

Comments
 (0)