Skip to content

Commit 348e56e

Browse files
authored
Add DelayParentScope scoping utility (#1951)
1 parent e82f9e2 commit 348e56e

File tree

4 files changed

+77
-7
lines changed

4 files changed

+77
-7
lines changed

docs/src/basics/Composition.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ With symbolic parameters, it is possible to set the default value of a parameter
133133
# ...
134134
sys = ODESystem(
135135
# ...
136-
# directly in the defauls argument
136+
# directly in the defaults argument
137137
defaults=Pair{Num, Any}[
138138
x => u,
139139
y => σ,
@@ -146,12 +146,41 @@ sys.y = u*1.1
146146
In a hierarchical system, variables of the subsystem get namespaced by the name of the system they are in. This prevents naming clashes, but also enforces that every state and parameter is local to the subsystem it is used in. In some cases it might be desirable to have variables and parameters that are shared between subsystems, or even global. This can be accomplished as follows.
147147

148148
```julia
149-
@variables a b c d
149+
@parameters t a b c d e f
150+
p = [
151+
a #a is a local variable
152+
ParentScope(b) # b is a variable that belongs to one level up in the hierarchy
153+
ParentScope(ParentScope(c))# ParentScope can be nested
154+
DelayParentScope(d) # skips one level before applying ParentScope
155+
DelayParentScope(e,2) # second argument allows skipping N levels
156+
GlobalScope(f) # global variables will never be namespaced
157+
]
150158

151-
# a is a local variable
152-
b = ParentScope(b) # b is a variable that belongs to one level up in the hierarchy
153-
c = ParentScope(ParentScope(c)) # ParentScope can be nested
154-
d = GlobalScope(d) # global variables will never be namespaced
159+
level0 = ODESystem(Equation[],t,[],p; name = :level0)
160+
level1 = ODESystem(Equation[],t,[],[];name = :level1) level0
161+
parameters(level1)
162+
#level0₊a
163+
#b
164+
#c
165+
#level0₊d
166+
#level0₊e
167+
#f
168+
level2 = ODESystem(Equation[],t,[],[];name = :level2) level1
169+
parameters(level2)
170+
#level1₊level0₊a
171+
#level1₊b
172+
#c
173+
#level0₊d
174+
#level1₊level0₊e
175+
#f
176+
level3 = ODESystem(Equation[],t,[],[];name = :level3) level2
177+
parameters(level3)
178+
#level2₊level1₊level0₊a
179+
#level2₊level1₊b
180+
#level2₊c
181+
#level2₊level0₊d
182+
#level1₊level0₊e
183+
#f
155184
```
156185

157186
## Structural Simplify

src/ModelingToolkit.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export PDESystem
200200
export Differential, expand_derivatives, @derivatives
201201
export Equation, ConstrainedEquation
202202
export Term, Sym
203-
export SymScope, LocalScope, ParentScope, GlobalScope
203+
export SymScope, LocalScope, ParentScope, DelayParentScope, GlobalScope
204204
export independent_variables, independent_variable, states, parameters, equations, controls,
205205
observed, structure, full_equations
206206
export structural_simplify, expand_connections, linearize, linearization_function

src/systems/abstractsystem.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,16 @@ function ParentScope(sym::Union{Num, Symbolic})
364364
setmetadata(sym, SymScope, ParentScope(getmetadata(value(sym), SymScope, LocalScope())))
365365
end
366366

367+
struct DelayParentScope <: SymScope
368+
parent::SymScope
369+
N::Int
370+
end
371+
function DelayParentScope(sym::Union{Num, Symbolic}, N)
372+
setmetadata(sym, SymScope,
373+
DelayParentScope(getmetadata(value(sym), SymScope, LocalScope()), N))
374+
end
375+
DelayParentScope(sym::Union{Num, Symbolic}) = DelayParentScope(sym, 1)
376+
367377
struct GlobalScope <: SymScope end
368378
GlobalScope(sym::Union{Num, Symbolic}) = setmetadata(sym, SymScope, GlobalScope())
369379

@@ -382,6 +392,15 @@ function renamespace(sys, x)
382392
rename(x, renamespace(getname(sys), getname(x)))
383393
elseif scope isa ParentScope
384394
setmetadata(x, SymScope, scope.parent)
395+
elseif scope isa DelayParentScope
396+
if scope.N > 0
397+
x = setmetadata(x, SymScope,
398+
DelayParentScope(scope.parent, scope.N - 1))
399+
rename(x, renamespace(getname(sys), getname(x)))
400+
else
401+
#rename(x, renamespace(getname(sys), getname(x)))
402+
setmetadata(x, SymScope, scope.parent)
403+
end
385404
else # GlobalScope
386405
x
387406
end

test/variable_scope.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,25 @@ end
4444
@test renamed([:foo :bar :baz], b) == Symbol("foo₊bar₊b")
4545
@test renamed([:foo :bar :baz], c) == Symbol("foo₊c")
4646
@test renamed([:foo :bar :baz], d) == :d
47+
48+
@parameters t a b c d e f
49+
p = [a
50+
ParentScope(b)
51+
ParentScope(ParentScope(c))
52+
DelayParentScope(d)
53+
DelayParentScope(e, 2)
54+
GlobalScope(f)]
55+
56+
level0 = ODESystem(Equation[], t, [], p; name = :level0)
57+
level1 = ODESystem(Equation[], t, [], []; name = :level1) level0
58+
level2 = ODESystem(Equation[], t, [], []; name = :level2) level1
59+
level3 = ODESystem(Equation[], t, [], []; name = :level3) level2
60+
61+
ps = ModelingToolkit.getname.(parameters(level3))
62+
63+
@test isequal(ps[1], :level2₊level1₊level0₊a)
64+
@test isequal(ps[2], :level2₊level1₊b)
65+
@test isequal(ps[3], :level2₊c)
66+
@test isequal(ps[4], :level2₊level0₊d)
67+
@test isequal(ps[5], :level1₊level0₊e)
68+
@test isequal(ps[6], :f)

0 commit comments

Comments
 (0)