Skip to content

Commit f8b9e14

Browse files
authored
Merge pull request #1348 from SciML/myb/tmpconnector
Expand connections after model instantiation and add stream connectors
2 parents 3fd2871 + 71a8e9d commit f8b9e14

19 files changed

+858
-255
lines changed

examples/electrical_components.jl

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,10 @@ using ModelingToolkit, OrdinaryDiffEq
33

44
@parameters t
55
@connector function Pin(;name)
6-
sts = @variables v(t)=1.0 i(t)=1.0
6+
sts = @variables v(t)=1.0 i(t)=1.0 [connect = Flow]
77
ODESystem(Equation[], t, sts, []; name=name)
88
end
99

10-
function ModelingToolkit.connect(::Type{Pin}, ps...)
11-
eqs = [
12-
0 ~ sum(p->p.i, ps) # KCL
13-
]
14-
# KVL
15-
for i in 1:length(ps)-1
16-
push!(eqs, ps[i].v ~ ps[i+1].v)
17-
end
18-
19-
return eqs
20-
end
21-
2210
function Ground(;name)
2311
@named g = Pin()
2412
eqs = [g.v ~ 0]

examples/rc_model.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ V = 1.0
1111
rc_eqs = [
1212
connect(source.p, resistor.p)
1313
connect(resistor.n, capacitor.p)
14-
connect(capacitor.n, source.n, ground.g)
14+
connect(capacitor.n, source.n)
15+
connect(capacitor.n, ground.g)
1516
]
1617

1718
@named rc_model = ODESystem(rc_eqs, t)

examples/serial_inductor.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ eqs = [
1010
connect(source.p, resistor.p)
1111
connect(resistor.n, inductor1.p)
1212
connect(inductor1.n, inductor2.p)
13-
connect(source.n, inductor2.n, ground.g)
13+
connect(source.n, inductor2.n)
14+
connect(inductor2.n, ground.g)
1415
]
1516

1617
@named ll_model = ODESystem(eqs, t)

src/ModelingToolkit.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ if !isdefined(Graphs, :IncrementalCycleTracker)
123123
end
124124

125125
include("systems/abstractsystem.jl")
126+
include("systems/connectors.jl")
126127

127128
include("systems/diffeqs/odesystem.jl")
128129
include("systems/diffeqs/sdesystem.jl")
@@ -157,8 +158,6 @@ for S in subtypes(ModelingToolkit.AbstractSystem)
157158
@eval convert_system(::Type{<:$S}, sys::$S) = sys
158159
end
159160

160-
struct Flow end
161-
162161
export AbstractTimeDependentSystem, AbstractTimeIndependentSystem, AbstractMultivariateSystem
163162
export ODESystem, ODEFunction, ODEFunctionExpr, ODEProblemExpr, convert_system
164163
export DAEFunctionExpr, DAEProblemExpr
@@ -173,7 +172,8 @@ export SteadyStateProblem, SteadyStateProblemExpr
173172
export JumpProblem, DiscreteProblem
174173
export NonlinearSystem, OptimizationSystem
175174
export ControlSystem
176-
export alias_elimination, flatten, connect, @connector
175+
export alias_elimination, flatten
176+
export connect, @connector, Connection, Flow, Stream, instream
177177
export ode_order_lowering, liouville_transform
178178
export runge_kutta_discretize
179179
export PDESystem
@@ -182,7 +182,7 @@ export Equation, ConstrainedEquation
182182
export Term, Sym
183183
export SymScope, LocalScope, ParentScope, GlobalScope
184184
export independent_variables, independent_variable, states, parameters, equations, controls, observed, structure
185-
export structural_simplify
185+
export structural_simplify, expand_connections
186186
export DiscreteSystem, DiscreteProblem
187187

188188
export calculate_jacobian, generate_jacobian, generate_function
@@ -204,7 +204,7 @@ export toexpr, get_variables
204204
export simplify, substitute
205205
export build_function
206206
export modelingtoolkitize
207-
export @variables, @parameters, Flow
207+
export @variables, @parameters
208208
export @named, @nonamespace, @namespace, extend, compose
209209

210210
end # module

src/systems/abstractsystem.jl

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ for prop in [
219219
:domain
220220
:ivs
221221
:dvs
222-
:connection_type
222+
:connector_type
223+
:connections
223224
:preface
224225
]
225226
fname1 = Symbol(:get_, prop)
@@ -282,7 +283,7 @@ function getvar(sys::AbstractSystem, name::Symbol; namespace=false)
282283
elseif !isempty(systems)
283284
i = findfirst(x->nameof(x)==name, systems)
284285
if i !== nothing
285-
return namespace ? rename(systems[i], renamespace(sys, name)) : systems[i]
286+
return namespace ? renamespace(sys, systems[i]) : systems[i]
286287
end
287288
end
288289

@@ -355,6 +356,7 @@ GlobalScope(sym::Union{Num, Symbolic}) = setmetadata(sym, SymScope, GlobalScope(
355356

356357
renamespace(sys, eq::Equation) = namespace_equation(eq, sys)
357358

359+
renamespace(names::AbstractVector, x) = foldr(renamespace, names, init=x)
358360
function renamespace(sys, x)
359361
x = unwrap(x)
360362
if x isa Symbolic
@@ -367,6 +369,8 @@ function renamespace(sys, x)
367369
x
368370
end
369371
end
372+
elseif x isa AbstractSystem
373+
rename(x, renamespace(sys, nameof(x)))
370374
else
371375
Symbol(getname(sys), :₊, x)
372376
end
@@ -562,7 +566,24 @@ function round_trip_expr(t, var2name)
562566
args = map(Base.Fix2(round_trip_expr, var2name), arguments(t))
563567
return :($f($(args...)))
564568
end
565-
round_trip_eq(eq, var2name) = Expr(:call, :~, round_trip_expr(eq.lhs, var2name), round_trip_expr(eq.rhs, var2name))
569+
570+
function round_trip_eq(eq::Equation, var2name)
571+
if eq.lhs isa Connection
572+
syss = get_systems(eq.rhs)
573+
call = Expr(:call, connect)
574+
for sys in syss
575+
strs = split(string(nameof(sys)), "")
576+
s = Symbol(strs[1])
577+
for st in strs[2:end]
578+
s = Expr(:., s, Meta.quot(Symbol(st)))
579+
end
580+
push!(call.args, s)
581+
end
582+
call
583+
else
584+
Expr(:call, (~), round_trip_expr(eq.lhs, var2name), round_trip_expr(eq.rhs, var2name))
585+
end
586+
end
566587

567588
function push_eqs!(stmt, eqs, var2name)
568589
eqs_name = gensym(:eqs)
@@ -854,6 +875,7 @@ topological sort of the observed equations. When `simplify=true`, the `simplify`
854875
function will be applied during the tearing process.
855876
"""
856877
function structural_simplify(sys::AbstractSystem; simplify=false)
878+
sys = expand_connections(sys)
857879
sys = initialize_system_structure(alias_elimination(sys))
858880
check_consistency(sys)
859881
if sys isa ODESystem
@@ -905,71 +927,6 @@ function check_eqs_u0(eqs, dvs, u0; check_length=true, kwargs...)
905927
return nothing
906928
end
907929

908-
###
909-
### Connectors
910-
###
911-
912-
function with_connection_type(expr)
913-
@assert expr isa Expr && (expr.head == :function || (expr.head == :(=) &&
914-
expr.args[1] isa Expr &&
915-
expr.args[1].head == :call))
916-
917-
sig = expr.args[1]
918-
body = expr.args[2]
919-
920-
fname = sig.args[1]
921-
args = sig.args[2:end]
922-
923-
quote
924-
struct $fname
925-
$(gensym()) -> 1 # this removes the default constructor
926-
end
927-
function $fname($(args...))
928-
function f()
929-
$body
930-
end
931-
res = f()
932-
$isdefined(res, :connection_type) ? $Setfield.@set!(res.connection_type = $fname) : res
933-
end
934-
end
935-
end
936-
937-
macro connector(expr)
938-
esc(with_connection_type(expr))
939-
end
940-
941-
promote_connect_rule(::Type{T}, ::Type{S}) where {T, S} = Union{}
942-
promote_connect_rule(::Type{T}, ::Type{T}) where {T} = T
943-
promote_connect_type(t1::Type, t2::Type, ts::Type...) = promote_connect_type(promote_connect_rule(t1, t2), ts...)
944-
@inline function promote_connect_type(::Type{T}, ::Type{S}) where {T,S}
945-
promote_connect_result(
946-
T,
947-
S,
948-
promote_connect_rule(T,S),
949-
promote_connect_rule(S,T)
950-
)
951-
end
952-
953-
promote_connect_result(::Type, ::Type, ::Type{T}, ::Type{Union{}}) where {T} = T
954-
promote_connect_result(::Type, ::Type, ::Type{Union{}}, ::Type{S}) where {S} = S
955-
promote_connect_result(::Type, ::Type, ::Type{T}, ::Type{T}) where {T} = T
956-
function promote_connect_result(::Type{T}, ::Type{S}, ::Type{P1}, ::Type{P2}) where {T,S,P1,P2}
957-
throw(ArgumentError("connection promotion for $T and $S resulted in $P1 and $P2. " *
958-
"Define promotion only in one direction."))
959-
end
960-
961-
throw_connector_promotion(T, S) = throw(ArgumentError("Don't know how to connect systems of type $S and $T"))
962-
promote_connect_result(::Type{T},::Type{S},::Type{Union{}},::Type{Union{}}) where {T,S} = throw_connector_promotion(T,S)
963-
964-
promote_connect_type(::Type{T}, ::Type{T}) where {T} = T
965-
function promote_connect_type(T, S)
966-
error("Don't know how to connect systems of type $S and $T")
967-
end
968-
969-
function connect(syss...)
970-
connect(promote_connect_type(map(get_connection_type, syss)...), syss...)
971-
end
972-
973930
###
974931
### Inheritance & composition
975932
###
@@ -990,7 +947,7 @@ function Base.hash(sys::AbstractSystem, s::UInt)
990947
end
991948

992949
"""
993-
$(TYPEDSIGNATURES)
950+
$(TYPEDSIGNATURES)
994951
995952
entend the `basesys` with `sys`, the resulting system would inherit `sys`'s name
996953
by default.
@@ -1026,7 +983,7 @@ end
1026983
Base.:(&)(sys::AbstractSystem, basesys::AbstractSystem; name::Symbol=nameof(sys)) = extend(sys, basesys; name=name)
1027984

1028985
"""
1029-
$(SIGNATURES)
986+
$(SIGNATURES)
1030987
1031988
compose multiple systems together. The resulting system would inherit the first
1032989
system's name.

0 commit comments

Comments
 (0)