Skip to content

Commit adfbb8e

Browse files
committed
Basically rewrite connectors
1 parent 24c01e5 commit adfbb8e

File tree

3 files changed

+53
-49
lines changed

3 files changed

+53
-49
lines changed

examples/electrical_components.jl

+1-15
Original file line numberDiff line numberDiff line change
@@ -3,24 +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}, c::Connection)
11-
@unpack outers, inners = c
12-
isum = isempty(inners) ? 0 : sum(p->p.i, inners)
13-
osum = isempty(outers) ? 0 : sum(p->p.i, outers)
14-
eqs = [0 ~ isum - osum] # KCL
15-
ps = [outers; inners]
16-
# KVL
17-
for i in 1:length(ps)-1
18-
push!(eqs, ps[i].v ~ ps[i+1].v)
19-
end
20-
21-
return eqs
22-
end
23-
2410
function Ground(;name)
2511
@named g = Pin()
2612
eqs = [g.v ~ 0]

src/systems/connectors.jl

+49-32
Original file line numberDiff line numberDiff line change
@@ -24,43 +24,22 @@ macro connector(expr)
2424
esc(with_connector_type(expr))
2525
end
2626

27-
function connector_type(sys::AbstractSystem)
28-
states(sys)
29-
end
27+
abstract type AbstractConnectorType end
28+
struct StreamConnector <: AbstractConnectorType end
29+
struct RegularConnector <: AbstractConnectorType end
3030

31-
promote_connect_rule(::Type{T}, ::Type{S}) where {T, S} = Union{}
32-
promote_connect_rule(::Type{T}, ::Type{T}) where {T} = T
33-
promote_connect_type(t1::Type, t2::Type, ts::Type...) = promote_connect_type(promote_connect_rule(t1, t2), ts...)
34-
@inline function promote_connect_type(::Type{T}, ::Type{S}) where {T,S}
35-
promote_connect_result(
36-
T,
37-
S,
38-
promote_connect_rule(T,S),
39-
promote_connect_rule(S,T)
40-
)
41-
end
42-
43-
promote_connect_result(::Type, ::Type, ::Type{T}, ::Type{Union{}}) where {T} = T
44-
promote_connect_result(::Type, ::Type, ::Type{Union{}}, ::Type{S}) where {S} = S
45-
promote_connect_result(::Type, ::Type, ::Type{T}, ::Type{T}) where {T} = T
46-
function promote_connect_result(::Type{T}, ::Type{S}, ::Type{P1}, ::Type{P2}) where {T,S,P1,P2}
47-
throw(ArgumentError("connection promotion for $T and $S resulted in $P1 and $P2. " *
48-
"Define promotion only in one direction."))
49-
end
50-
51-
throw_connector_promotion(T, S) = throw(ArgumentError("Don't know how to connect systems of type $S and $T"))
52-
promote_connect_result(::Type{T},::Type{S},::Type{Union{}},::Type{Union{}}) where {T,S} = throw_connector_promotion(T,S)
53-
54-
promote_connect_type(::Type{T}, ::Type{T}) where {T} = T
55-
function promote_connect_type(T, S)
56-
error("Don't know how to connect systems of type $S and $T")
31+
function connector_type(sys::AbstractSystem)
32+
sts = states(sys)
33+
#TODO: check the criteria for stream connectors
34+
any(s->getmetadata(s, ModelingToolkit.VariableConnectType, nothing) === Stream, sts) ? StreamConnector() : RegularConnector()
5735
end
5836

5937
Base.@kwdef struct Connection
6038
inners = nothing
6139
outers = nothing
6240
end
6341

42+
# everything is inner by default until we expand the connections
6443
Connection(syss) = Connection(inners=syss)
6544
get_systems(c::Connection) = c.inners
6645

@@ -78,12 +57,51 @@ function Base.show(io::IO, c::Connection)
7857
end
7958
end
8059

81-
function connect(syss...)
60+
function connect(syss::AbstractSystem...)
8261
length(syss) >= 2 || error("connect takes at least two systems!")
8362
length(unique(nameof, syss)) == length(syss) || error("connect takes distinct systems!")
8463
Equation(Connection(), Connection(syss)) # the RHS are connected systems
8564
end
8665

66+
function connect(c::Connection; check=true)
67+
@unpack inners, outers = c
68+
69+
flow_eqs = Equation[]
70+
other_eqs = Equation[]
71+
72+
cnts = Iterators.flatten((inners, outers))
73+
fs, ss = Iterators.peel(cnts)
74+
splitting_idx = length(inners) # anything after the splitting_idx is outer.
75+
first_sts = get_states(fs)
76+
first_sts_set = Set(getname.(first_sts))
77+
for sys in ss
78+
current_sts = getname.(get_states(sys))
79+
Set(current_sts) == first_sts_set || error("$(nameof(sys)) ($current_sts) doesn't match the connection type of $(nameof(fs)) ($first_sts).")
80+
end
81+
82+
ceqs = Equation[]
83+
for s in first_sts
84+
name = getname(s)
85+
isflow = getmetadata(s, VariableConnectType, Equality) === Flow
86+
rhs = 0 # only used for flow variables
87+
fix_val = getproperty(fs, name) # used for equality connections
88+
for (i, c) in enumerate(cnts)
89+
isinner = i <= splitting_idx
90+
# https://specification.modelica.org/v3.4/Ch15.html
91+
var = getproperty(c, name)
92+
if isflow
93+
rhs += isinner ? var : -var
94+
else
95+
i == 1 && continue # skip the first iteration
96+
push!(ceqs, fix_val ~ getproperty(c, name))
97+
end
98+
end
99+
isflow && push!(ceqs, 0 ~ rhs)
100+
end
101+
102+
return ceqs
103+
end
104+
87105
isconnector(s::AbstractSystem) = has_connector_type(s) && get_connector_type(s) !== nothing
88106

89107
function isouterconnector(sys::AbstractSystem; check=true)
@@ -165,8 +183,7 @@ function expand_connections(sys::AbstractSystem; debug=false)
165183
end
166184

167185
for c in narg_connects
168-
T = promote_connect_type(map(get_connector_type, c.outers)..., map(get_connector_type, c.inners)...)
169-
ceqs = connect(T, c)
186+
ceqs = connect(c)
170187
ceqs isa Equation ? push!(eqs, ceqs) : append!(eqs, ceqs)
171188
end
172189

src/variables.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ Symbolics.option_to_metadata_type(::Val{:input}) = VariableInput
1212
Symbolics.option_to_metadata_type(::Val{:output}) = VariableOutput
1313

1414
abstract type AbstractConnectType end
15-
struct Flow <: AbstractConnectType end # sum to 0
16-
struct Stream <: AbstractConnectType end # special stream connector
15+
struct Equality <: AbstractConnectType end # Equality connection
16+
struct Flow <: AbstractConnectType end # sum to 0
17+
struct Stream <: AbstractConnectType end # special stream connector
1718

1819
function isvarkind(m, x)
1920
p = getparent(x, nothing)

0 commit comments

Comments
 (0)