@@ -38,8 +38,8 @@ function connector_type(sys::AbstractSystem)
38
38
vtype === Stream && (n_stream += 1 )
39
39
vtype === Flow && (n_flow += 1 )
40
40
end
41
- (n_stream > 1 && n_flow > 1 ) && error (" There are multiple flow variables in $(nameof (sys)) !" )
42
- n_stream > 1 ? StreamConnector () : RegularConnector ()
41
+ (n_stream > 0 && n_flow > 1 ) && error (" There are multiple flow variables in $(nameof (sys)) !" )
42
+ n_stream > 0 ? StreamConnector () : RegularConnector ()
43
43
end
44
44
45
45
Base. @kwdef struct Connection
120
120
instream (a) = term (instream, unwrap (a), type= symtype (a))
121
121
122
122
isconnector (s:: AbstractSystem ) = has_connector_type (s) && get_connector_type (s) != = nothing
123
- isstreamconnector (s:: AbstractSystem ) = isconnector (s) && get_connector_type (s) === Stream
123
+ isstreamconnector (s:: AbstractSystem ) = isconnector (s) && get_connector_type (s) isa StreamConnector
124
+ isstreamconnection (c:: Connection ) = any (isstreamconnector, c. inners) || any (isstreamconnector, c. outers)
124
125
125
126
print_with_indent (n, x) = println (" " ^ n, x)
126
127
@@ -176,6 +177,18 @@ function split_sys_var(var)
176
177
connector_name, streamvar_name
177
178
end
178
179
180
+ function flowvar (sys:: AbstractSystem )
181
+ sts = get_states (sys)
182
+ for s in sts
183
+ vtype = getmetadata (s, ModelingToolkit. VariableConnectType, nothing )
184
+ vtype === Flow && return s
185
+ end
186
+ error (" There in no flow variable in $(nameof (sys)) " )
187
+ end
188
+
189
+ positivemax (m, :: Any ; tol= nothing )= max (m, something (tol, 1e-8 ))
190
+
191
+ #=
179
192
function find_connection(connector_name, ogsys, names)
180
193
cs = get_connections(ogsys)
181
194
cs === nothing || for c in cs
@@ -193,17 +206,6 @@ function find_connection(connector_name, ogsys, names)
193
206
error("$connector_name cannot be found in $(nameof(ogsys)) with levels $(names)")
194
207
end
195
208
196
- function flowvar (sys:: AbstractSystem )
197
- sts = get_states (sys)
198
- for s in sts
199
- vtype = getmetadata (s, ModelingToolkit. VariableConnectType, nothing )
200
- vtype === Flow && return s
201
- end
202
- error (" There in no flow variable in $(nameof (sys)) " )
203
- end
204
-
205
- positivemax (m, :: Any ; tol= nothing )= max (m, something (tol, 1e-8 ))
206
-
207
209
function expand_instream(ogsys, sys::AbstractSystem=ogsys, names=[]; debug=false, tol=nothing)
208
210
subsys = get_systems(sys)
209
211
isempty(subsys) && return sys
@@ -373,6 +375,7 @@ function expand_instream(ogsys, sys::AbstractSystem=ogsys, names=[]; debug=false
373
375
@set! sys.eqs = [eqs; instream_eqs; additional_eqs]
374
376
return sys
375
377
end
378
+ =#
376
379
377
380
function expand_connections (sys:: AbstractSystem ; debug= false )
378
381
sys = collect_connections (sys; debug= debug)
@@ -402,15 +405,27 @@ function collect_connections(sys::AbstractSystem; debug=false)
402
405
end
403
406
end
404
407
408
+ sys = flatten (sys)
405
409
eqs′ = get_eqs (sys)
406
410
eqs = Equation[]
411
+ instream_eqs = Equation[]
412
+ instream_exprs = []
407
413
cts = [] # connections
408
414
for eq in eqs′
409
- eq. lhs isa Connection ? push! (cts, get_systems (eq. rhs)) : push! (eqs, eq) # split connections and equations
415
+ if eq. lhs isa Connection
416
+ push! (cts, get_systems (eq. rhs))
417
+ elseif collect_instream! (instream_exprs, eq)
418
+ push! (instream_eqs, eq)
419
+ else
420
+ push! (eqs, eq) # split connections and equations
421
+ end
410
422
end
411
423
412
424
# if there are no connections, we are done
413
- isempty (cts) && return sys
425
+ if isempty (cts)
426
+ isempty (instream_eqs) || error (" Illegal instream function in $(nameof (sys)) " )
427
+ return sys
428
+ end
414
429
415
430
sys2idx = Dict {Symbol,Int} () # system (name) to n-th connect statement
416
431
narg_connects = Connection[]
@@ -476,6 +491,154 @@ function collect_connections(sys::AbstractSystem; debug=false)
476
491
println (" =============END=================" )
477
492
end
478
493
479
- @set! sys. eqs = eqs
494
+ # stream variables
495
+ stream_connects = filter (isstreamconnection, narg_connects)
496
+ @show length (stream_connects)
497
+ instream_eqs, additional_eqs = expand_instream (instream_eqs, instream_exprs, stream_connects; debug= debug)
498
+
499
+ @set! sys. eqs = [eqs; instream_eqs; additional_eqs]
480
500
return sys
481
501
end
502
+
503
+ function expand_instream (instream_eqs, instream_exprs, connects; debug= false )
504
+ sub = Dict ()
505
+ seen = Set ()
506
+ for ex in instream_exprs
507
+ var = only (arguments (ex))
508
+ connector_name, streamvar_name = split_sys_var (var)
509
+
510
+ # find the connect
511
+ cidx = findfirst (c-> connector_name in c, connects)
512
+ cidx === nothing && error (" $var is not a variable inside stream connectors" )
513
+ connect = connects[cidx]
514
+ connectors = Iterators. flatten ((connect. inners, connect. outers))
515
+ # stream variable
516
+ sv = getproperty (first (connectors), streamvar_name; namespace= false )
517
+ inner_sc = connect. inners
518
+ outer_sc = connect. outers
519
+
520
+ n_outers = length (outer_sc)
521
+ n_inners = length (inner_sc)
522
+ outer_names = (nameof (s) for s in outer_sc)
523
+ inner_names = (nameof (s) for s in inner_sc)
524
+ if debug
525
+ println (" Expanding: $ex " )
526
+ isempty (inner_names) || println (" Inner connectors: $(collect (inner_names)) " )
527
+ isempty (outer_names) || println (" Outer connectors: $(collect (outer_names)) " )
528
+ end
529
+
530
+ # expand `instream`s
531
+ # https://specification.modelica.org/v3.4/Ch15.html
532
+ # Based on the above requirements, the following implementation is
533
+ # recommended:
534
+ if n_inners == 1 && n_outers == 0
535
+ connector_name === only (inner_names) || error (" $var is not in any stream connector of $(nameof (ogsys)) " )
536
+ sub[ex] = var
537
+ elseif n_inners == 2 && n_outers == 0
538
+ @info connector_name collect (inner_names) length (inner_sc)
539
+ connector_name in inner_names || error (" $var is not in any stream connector of $(nameof (ogsys)) " )
540
+ idx = findfirst (c-> nameof (c) === connector_name, inner_sc)
541
+ other = idx == 1 ? 2 : 1
542
+ sub[ex] = states (inner_sc[other], sv)
543
+ elseif n_inners == 1 && n_outers == 1
544
+ isinner = connector_name === only (inner_names)
545
+ isouter = connector_name === only (outer_names)
546
+ (isinner || isouter) || error (" $var is not in any stream connector of $(nameof (ogsys)) " )
547
+ if isinner
548
+ outerstream = states (only (outer_sc), sv) # c_1.h_outflow
549
+ sub[ex] = outerstream
550
+ end
551
+ else
552
+ fv = flowvar (first (connectors))
553
+ idx = findfirst (c-> nameof (c) === connector_name, inner_sc)
554
+ if idx != = nothing
555
+ si = sum (s-> max (states (s, fv), 0 ), outer_sc)
556
+ for j in 1 : n_inners; j == i && continue
557
+ f = states (inner_sc[j], fv)
558
+ si += max (- f, 0 )
559
+ end
560
+
561
+ num = 0
562
+ den = 0
563
+ for j in 1 : n_inners; j == i && continue
564
+ f = states (inner_sc[j], fv)
565
+ tmp = positivemax (- f, si; tol= tol)
566
+ den += tmp
567
+ num += tmp * states (inner_sc[j], sv)
568
+ end
569
+ for k in 1 : n_outers
570
+ f = states (outer_sc[k], fv)
571
+ tmp = positivemax (f, si; tol= tol)
572
+ den += tmp
573
+ num += tmp * instream (states (outer_sc[k], sv))
574
+ end
575
+ sub[ex] = num / den
576
+ end
577
+
578
+ end
579
+ end
580
+
581
+ # additional equations
582
+ additional_eqs = Equation[]
583
+ for c in connects
584
+ outer_sc = c. outers
585
+ isempty (outer_sc) && continue
586
+ inner_sc = c. inners
587
+ n_outers = length (outer_sc)
588
+ n_inners = length (inner_sc)
589
+ for sv in get_states (first (outer_sc))
590
+ vtype = getmetadata (sv, ModelingToolkit. VariableConnectType, nothing )
591
+ vtype === Stream || continue
592
+ if n_inners == 1 && n_outers == 1
593
+ innerstream = states (only (inner_sc), sv)
594
+ outerstream = states (only (outer_sc), sv)
595
+ push! (additional_eqs, outerstream ~ innerstream)
596
+ elseif n_inners == 0 && n_outers == 2
597
+ # we don't expand `instream` in this case.
598
+ v1 = states (outer_sc[1 ], sv)
599
+ v2 = states (outer_sc[2 ], sv)
600
+ push! (additional_eqs, v1 ~ instream (v2))
601
+ push! (additional_eqs, v2 ~ instream (v1))
602
+ else
603
+ for q in 1 : n_outers
604
+ sq += sum (s-> max (- states (s, fv), 0 ), inner_sc)
605
+ for k in 1 : n_outers; k == q && continue
606
+ f = states (outer_sc[j], fv)
607
+ si += max (f, 0 )
608
+ end
609
+
610
+ num = 0
611
+ den = 0
612
+ for j in 1 : n_inners
613
+ f = states (inner_sc[j], fv)
614
+ tmp = positivemax (- f, sq; tol= tol)
615
+ den += tmp
616
+ num += tmp * states (inner_sc[j], sv)
617
+ end
618
+ for k in 1 : n_outers; k == q && continue
619
+ f = states (outer_sc[k], fv)
620
+ tmp = positivemax (f, sq; tol= tol)
621
+ den += tmp
622
+ num += tmp * instream (states (outer_sc[k], sv))
623
+ end
624
+ push! (additional_eqs, states (outer_sc[q], sv) ~ num / den)
625
+ end
626
+ end
627
+ end
628
+ end
629
+
630
+ instream_eqs = map (Base. Fix2 (substitute, sub), instream_eqs)
631
+ if debug
632
+ println (" Expanded equations:" )
633
+ for eq in instream_eqs
634
+ print_with_indent (4 , eq)
635
+ end
636
+ if ! isempty (additional_eqs)
637
+ println (" Additional equations:" )
638
+ for eq in additional_eqs
639
+ print_with_indent (4 , eq)
640
+ end
641
+ end
642
+ end
643
+ return instream_eqs, additional_eqs
644
+ end
0 commit comments