|
244 | 244 | Base.hash(l::ConnectionElement, salt::UInt) = hash(nameof(l.sys)) ⊻ hash(l.v) ⊻ hash(l.isouter) ⊻ salt
|
245 | 245 | Base.isequal(l1::ConnectionElement, l2::ConnectionElement) = l1 == l2
|
246 | 246 | 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) |
251 | 249 |
|
252 | 250 | struct ConnectionSet
|
253 | 251 | 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})
|
550 | 548 | end
|
551 | 549 | SymbolicUtils.promote_symtype(::typeof(instream_rt), ::Vararg) = Real
|
552 | 550 |
|
| 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 | + |
553 | 704 | function expand_instream(instream_eqs, instream_exprs, connects; debug=false, tol)
|
554 | 705 | sub = Dict()
|
555 |
| - seen = Set() |
556 | 706 | for ex in instream_exprs
|
557 | 707 | var = only(arguments(ex))
|
558 | 708 | connector_name, streamvar_name = split_sys_var(var)
|
|
0 commit comments