Skip to content

Commit 73c39b2

Browse files
committed
Add expand_instream2
1 parent 0b0f784 commit 73c39b2

File tree

1 file changed

+155
-5
lines changed

1 file changed

+155
-5
lines changed

src/systems/connectors.jl

Lines changed: 155 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,8 @@ end
244244
Base.hash(l::ConnectionElement, salt::UInt) = hash(nameof(l.sys)) hash(l.v) hash(l.isouter) salt
245245
Base.isequal(l1::ConnectionElement, l2::ConnectionElement) = l1 == l2
246246
Base.:(==)(l1::ConnectionElement, l2::ConnectionElement) = nameof(l1.sys) == nameof(l2.sys) && isequal(l1.v, l2.v) && l1.isouter == l2.isouter
247-
function namespaced_var(l::ConnectionElement)
248-
@unpack sys, v = l
249-
states(copy(sys), v)
250-
end
247+
namespaced_var(l::ConnectionElement) = states(l, l.v)
248+
states(l::ConnectionElement, v) = states(copy(l.sys), v)
251249

252250
struct ConnectionSet
253251
set::Vector{ConnectionElement} # namespace.sys, var, isouter
@@ -550,9 +548,161 @@ function instream_rt(ins::Val{inner_n}, outs::Val{outer_n}, vars::Vararg{Any,N})
550548
end
551549
SymbolicUtils.promote_symtype(::typeof(instream_rt), ::Vararg) = Real
552550

551+
function expand_instream2(csets::AbstractVector{<:ConnectionSet}, sys::AbstractSystem, namespace=nothing, debug=false, tol=1e-8)
552+
subsys = get_systems(sys)
553+
# no connectors if there are no subsystems
554+
isempty(subsys) && return sys
555+
# post order traversal
556+
@set! sys.systems = map(s->expand_instream2(csets, s, renamespace(namespace, nameof(s)), debug, tol), subsys)
557+
558+
eqs′ = get_eqs(sys)
559+
eqs = Equation[]
560+
instream_eqs = Equation[]
561+
instream_exprs = []
562+
for eq in eqs′
563+
if collect_instream!(instream_exprs, eq)
564+
push!(instream_eqs, eq)
565+
else
566+
push!(eqs, eq) # split connections and equations
567+
end
568+
end
569+
570+
571+
sub = Dict()
572+
for ex in instream_exprs
573+
sv = only(arguments(ex))
574+
full_name_sv = renamespace(namespace, sv)
575+
576+
#cidx = findfirst(c->any(v->, ), )
577+
cidx = -1
578+
idx_in_set = -1
579+
for (i, c) in enumerate(csets)
580+
for (j, v) in enumerate(c.set)
581+
if isequal(namespaced_var(v), full_name_sv)
582+
cidx = i
583+
idx_in_set = j
584+
end
585+
end
586+
end
587+
cidx < 0 && error("$sv is not a variable inside stream connectors")
588+
cset = csets[cidx].set
589+
590+
connectors = Vector{Any}(undef, length(cset))
591+
n_inners = n_outers = 0
592+
for (i, e) in enumerate(cset)
593+
connectors[i] = e.sys.sys
594+
if e.isouter
595+
n_outers += 1
596+
else
597+
n_inners += 1
598+
end
599+
end
600+
if n_inners == 1 && n_outers == 0
601+
sub[ex] = sv
602+
elseif n_inners == 2 && n_outers == 0
603+
other = idx_in_set == 1 ? 2 : 1
604+
sub[ex] = states(cset[other], sv)
605+
elseif n_inners == 1 && n_outers == 1
606+
if !cset[idx_in_set].isouter
607+
other = idx_in_set == 1 ? 2 : 1
608+
outerstream = states(cset[other], sv)
609+
sub[ex] = outerstream
610+
end
611+
else
612+
if !cset[idx_in_set].isouter
613+
fv = flowvar(first(connectors))
614+
# mj.c.m_flow
615+
innerfvs = [unwrap(states(s, fv)) for (j, s) in enumerate(cset) if j != idx_in_set && !s.isouter]
616+
innersvs = [unwrap(states(s, sv)) for (j, s) in enumerate(cset) if j != idx_in_set && !s.isouter]
617+
# ck.m_flow
618+
outerfvs = [unwrap(states(s, fv)) for s in cset if s.isouter]
619+
outersvs = [unwrap(states(s, sv)) for s in cset if s.isouter]
620+
621+
sub[ex] = term(instream_rt, Val(length(innerfvs)), Val(length(outerfvs)), innerfvs..., innersvs..., outerfvs..., outersvs...)
622+
end
623+
end
624+
end
625+
626+
# additional equations
627+
additional_eqs = Equation[]
628+
csets = filter(cset->any(e->e.sys.namespace === namespace, cset.set), csets)
629+
for cset′ in csets
630+
cset = cset′.set
631+
connectors = Vector{Any}(undef, length(cset))
632+
n_inners = n_outers = 0
633+
for (i, e) in enumerate(cset)
634+
connectors[i] = e.sys.sys
635+
if e.isouter
636+
n_outers += 1
637+
else
638+
n_inners += 1
639+
end
640+
end
641+
iszero(n_outers) && continue
642+
connector_representative = first(cset).sys.sys
643+
fv = flowvar(connector_representative)
644+
sv = first(cset).v
645+
vtype = get_connection_type(sv)
646+
vtype === Stream || continue
647+
if n_inners == 1 && n_outers == 1
648+
push!(additional_eqs, states(cset[1], sv) ~ states(cset[2], sv))
649+
elseif n_inners == 0 && n_outers == 2
650+
# we don't expand `instream` in this case.
651+
v1 = states(cset[1], sv)
652+
v2 = states(cset[2], sv)
653+
push!(additional_eqs, v1 ~ instream(v2))
654+
push!(additional_eqs, v2 ~ instream(v1))
655+
else
656+
sq = 0
657+
s_inners = (s for s in cset if !s.isouter)
658+
s_outers = (s for s in cset if s.isouter)
659+
for (q, oscq) in enumerate(s_outers)
660+
sq += sum(s->max(-states(s, fv), 0), s_inners)
661+
for (k, s) in enumerate(s_outers); k == q && continue
662+
f = states(s, fv)
663+
sq += max(f, 0)
664+
end
665+
666+
num = 0
667+
den = 0
668+
for s in s_inners
669+
f = states(s, fv)
670+
tmp = positivemax(-f, sq; tol=tol)
671+
den += tmp
672+
num += tmp * states(s, sv)
673+
end
674+
for (k, s) in enumerate(s_outers); k == q && continue
675+
f = states(s, fv)
676+
tmp = positivemax(f, sq; tol=tol)
677+
den += tmp
678+
num += tmp * instream(states(s, sv))
679+
end
680+
push!(additional_eqs, states(oscq, sv) ~ num / den)
681+
end
682+
end
683+
end
684+
685+
instream_eqs = map(Base.Fix2(substitute, sub), instream_eqs)
686+
if debug
687+
println("===========BEGIN=============")
688+
println("Expanded equations:")
689+
for eq in instream_eqs
690+
print_with_indent(4, eq)
691+
end
692+
if !isempty(additional_eqs)
693+
println("Additional equations:")
694+
for eq in additional_eqs
695+
print_with_indent(4, eq)
696+
end
697+
end
698+
println("============END==============")
699+
end
700+
701+
@set! sys.eqs = [eqs; instream_eqs; additional_eqs]
702+
end
703+
553704
function expand_instream(instream_eqs, instream_exprs, connects; debug=false, tol)
554705
sub = Dict()
555-
seen = Set()
556706
for ex in instream_exprs
557707
var = only(arguments(ex))
558708
connector_name, streamvar_name = split_sys_var(var)

0 commit comments

Comments
 (0)