@@ -315,7 +315,34 @@ function ori(sys)
315
315
end
316
316
end
317
317
318
- function connection2set! (connectionsets, namespace, ss, isouter)
318
+ """
319
+ $(TYPEDSIGNATURES)
320
+
321
+ Populate `connectionsets` with connections between the connectors `ss`, all of which are
322
+ namespaced by `namespace`.
323
+
324
+ # Keyword Arguments
325
+ - `ignored_connects`: A tuple of the systems and variables for which connections should be
326
+ ignored. Of the format returned from `as_hierarchy`.
327
+ - `namespaced_ignored_systems`: The `from_hierarchy` versions of entries in
328
+ `ignored_connects[1]`, purely to avoid unnecessary recomputation.
329
+ """
330
+ function connection2set! (connectionsets, namespace, ss, isouter;
331
+ ignored_connects = (HierarchySystemT[], HierarchyVariableT[]),
332
+ namespaced_ignored_systems = ODESystem[])
333
+ ignored_systems, ignored_variables = ignored_connects
334
+ # ignore specified systems
335
+ ss = filter (ss) do s
336
+ all (namespaced_ignored_systems) do igsys
337
+ nameof (igsys) != nameof (s)
338
+ end
339
+ end
340
+ # `ignored_variables` for each `s` in `ss`
341
+ corresponding_ignored_variables = map (
342
+ Base. Fix2 (ignored_systems_for_subsystem, ignored_variables), ss)
343
+ corresponding_namespaced_ignored_variables = map (
344
+ Broadcast. BroadcastFunction (from_hierarchy), corresponding_ignored_variables)
345
+
319
346
regular_ss = []
320
347
domain_ss = nothing
321
348
for s in ss
@@ -340,9 +367,12 @@ function connection2set!(connectionsets, namespace, ss, isouter)
340
367
for (i, s) in enumerate (ss)
341
368
sts = unknowns (s)
342
369
io = isouter (s)
343
- for (j, v) in enumerate (sts)
370
+ _ignored_variables = corresponding_ignored_variables[i]
371
+ _namespaced_ignored_variables = corresponding_namespaced_ignored_variables[i]
372
+ for v in sts
344
373
vtype = get_connection_type (v)
345
374
(vtype === Flow && isequal (v, dv)) || continue
375
+ any (isequal (v), _namespaced_ignored_variables) && continue
346
376
push! (cset, T (LazyNamespace (namespace, domain_ss), dv, false ))
347
377
push! (cset, T (LazyNamespace (namespace, s), v, io))
348
378
end
@@ -360,6 +390,12 @@ function connection2set!(connectionsets, namespace, ss, isouter)
360
390
end
361
391
sts1 = Set (sts1v)
362
392
num_unknowns = length (sts1)
393
+
394
+ # we don't filter here because `csets` should include the full set of unknowns.
395
+ # not all of `ss` will have the same (or any) variables filtered so the ones
396
+ # that aren't should still go in the right cset. Since `sts1` is only used for
397
+ # validating that all systems being connected are of the same type, it has
398
+ # unfiltered entries.
363
399
csets = [T[] for _ in 1 : num_unknowns] # Add 9 orientation variables if connection is between multibody frames
364
400
for (i, s) in enumerate (ss)
365
401
unknown_vars = unknowns (s)
@@ -372,7 +408,10 @@ function connection2set!(connectionsets, namespace, ss, isouter)
372
408
all (Base. Fix2 (in, sts1), unknown_vars)) ||
373
409
connection_error (ss))
374
410
io = isouter (s)
411
+ # don't `filter!` here so that `j` points to the correct cset regardless of
412
+ # which variables are filtered.
375
413
for (j, v) in enumerate (unknown_vars)
414
+ any (isequal (v), corresponding_namespaced_ignored_variables[i]) && continue
376
415
push! (csets[j], T (LazyNamespace (namespace, s), v, io))
377
416
end
378
417
end
@@ -395,16 +434,48 @@ function generate_connection_set(
395
434
connectionsets = ConnectionSet[]
396
435
domain_csets = ConnectionSet[]
397
436
sys = generate_connection_set! (
398
- connectionsets, domain_csets, sys, find, replace, scalarize)
437
+ connectionsets, domain_csets, sys, find, replace, scalarize, nothing ,
438
+ # include systems to be ignored
439
+ ignored_connections (sys))
399
440
csets = merge (connectionsets)
400
441
domain_csets = merge ([csets; domain_csets], true )
401
442
402
443
sys, (csets, domain_csets)
403
444
end
404
445
446
+ """
447
+ $(TYPEDSIGNATURES)
448
+
449
+ Generate connection sets from `connect` equations.
450
+
451
+ # Arguments
452
+
453
+ - `connectionsets` is the list of connection sets to be populated by recursively
454
+ descending `sys`.
455
+ - `domain_csets` is the list of connection sets for domain connections.
456
+ - `sys` is the system whose equations are to be searched.
457
+ - `namespace` is a system representing the namespace in which `sys` exists, or `nothing`
458
+ for no namespace (if `sys` is top-level).
459
+ - `ignored_connects` is a tuple. The first (second) element is a list of systems
460
+ (variables) in the format returned by `as_hierarchy` to be ignored when generating
461
+ connections. This is typically because the connections they are used in were removed by
462
+ analysis point transformations.
463
+ """
405
464
function generate_connection_set! (connectionsets, domain_csets,
406
- sys:: AbstractSystem , find, replace, scalarize, namespace = nothing )
465
+ sys:: AbstractSystem , find, replace, scalarize, namespace = nothing ,
466
+ ignored_connects = (HierarchySystemT[], HierarchyVariableT[]))
407
467
subsys = get_systems (sys)
468
+ ignored_systems, ignored_variables = ignored_connects
469
+ # turn hierarchies into namespaced systems
470
+ namespaced_ignored_systems = from_hierarchy .(ignored_systems)
471
+ namespaced_ignored_variables = from_hierarchy .(ignored_variables)
472
+ namespaced_ignored = (namespaced_ignored_systems, namespaced_ignored_variables)
473
+ # filter the subsystems of `sys` to exclude ignored ones
474
+ filtered_subsys = filter (subsys) do ss
475
+ all (namespaced_ignored_systems) do igsys
476
+ nameof (igsys) != nameof (ss)
477
+ end
478
+ end
408
479
409
480
isouter = generate_isouter (sys)
410
481
eqs′ = get_eqs (sys)
@@ -430,7 +501,8 @@ function generate_connection_set!(connectionsets, domain_csets,
430
501
neweq isa AbstractArray ? append! (eqs, neweq) : push! (eqs, neweq)
431
502
else
432
503
if lhs isa Connection && get_systems (lhs) === :domain
433
- connection2set! (domain_csets, namespace, get_systems (rhs), isouter)
504
+ connection2set! (domain_csets, namespace, get_systems (rhs), isouter;
505
+ ignored_connects, namespaced_ignored_systems)
434
506
elseif isconnection (rhs)
435
507
push! (cts, get_systems (rhs))
436
508
else
@@ -446,17 +518,23 @@ function generate_connection_set!(connectionsets, domain_csets,
446
518
447
519
# all connectors are eventually inside connectors.
448
520
T = ConnectionElement
449
- for s in subsys
521
+ # only generate connection sets for systems that are not ignored
522
+ for s in filtered_subsys
450
523
isconnector (s) || continue
451
524
is_domain_connector (s) && continue
525
+ _ignored_variables = ignored_systems_for_subsystem (s, ignored_variables)
526
+ _namespaced_ignored_variables = from_hierarchy .(_ignored_variables)
452
527
for v in unknowns (s)
453
528
Flow === get_connection_type (v) || continue
529
+ # ignore specified variables
530
+ any (isequal (v), _namespaced_ignored_variables) && continue
454
531
push! (connectionsets, ConnectionSet ([T (LazyNamespace (namespace, s), v, false )]))
455
532
end
456
533
end
457
534
458
535
for ct in cts
459
- connection2set! (connectionsets, namespace, ct, isouter)
536
+ connection2set! (connectionsets, namespace, ct, isouter;
537
+ ignored_connects, namespaced_ignored_systems)
460
538
end
461
539
462
540
# pre order traversal
@@ -465,12 +543,38 @@ function generate_connection_set!(connectionsets, domain_csets,
465
543
end
466
544
@set! sys. systems = map (
467
545
s -> generate_connection_set! (connectionsets, domain_csets, s,
468
- find, replace, scalarize,
469
- renamespace (namespace, s )),
546
+ find, replace, scalarize, renamespace (namespace, s),
547
+ ignored_systems_for_subsystem .((s,), ignored_connects )),
470
548
subsys)
471
549
@set! sys. eqs = eqs
472
550
end
473
551
552
+ """
553
+ $(TYPEDSIGNATURES)
554
+
555
+ Given a subsystem `subsys` of a parent system and a list of systems (variables) to be
556
+ ignored by `generate_connection_set!` (`expand_variable_connections`), filter
557
+ `ignored_systems` to only include those present in the subtree of `subsys` and update
558
+ their hierarchy to not include `subsys`.
559
+ """
560
+ function ignored_systems_for_subsystem (
561
+ subsys:: AbstractSystem , ignored_systems:: Vector{<:HierarchyT} )
562
+ result = eltype (ignored_systems)[]
563
+ # in case `subsys` is namespaced, get its hierarchy and compare suffixes
564
+ # instead of the just the last element
565
+ suffix = reverse! (namespace_hierarchy (nameof (subsys)))
566
+ N = length (suffix)
567
+ for igsys in ignored_systems
568
+ if igsys[(end - N + 1 ): end ] == suffix
569
+ push! (result, copy (igsys))
570
+ for i in 1 : N
571
+ pop! (result[end ])
572
+ end
573
+ end
574
+ end
575
+ return result
576
+ end
577
+
474
578
function Base. merge (csets:: AbstractVector{<:ConnectionSet} , allouter = false )
475
579
ele2idx = Dict {ConnectionElement, Int} ()
476
580
idx2ele = ConnectionElement[]
@@ -576,16 +680,25 @@ end
576
680
Recursively descend through the hierarchy of `sys` and expand all connection equations
577
681
of causal variables. Return the modified system.
578
682
"""
579
- function expand_variable_connections (sys:: AbstractSystem )
683
+ function expand_variable_connections (sys:: AbstractSystem ; ignored_variables = nothing )
684
+ if ignored_variables === nothing
685
+ ignored_variables = ignored_connections (sys)[2 ]
686
+ end
687
+ namespaced_ignored = from_hierarchy .(ignored_variables)
580
688
eqs = copy (get_eqs (sys))
581
689
valid_idxs = trues (length (eqs))
582
690
additional_eqs = Equation[]
583
691
584
692
for (i, eq) in enumerate (eqs)
585
693
eq. lhs isa Connection || continue
586
694
connection = eq. rhs
587
- elements = connection. systems
695
+ elements = get_systems ( connection)
588
696
is_causal_variable_connection (connection) || continue
697
+ elements = filter (elements) do el
698
+ all (namespaced_ignored) do var
699
+ getname (var) != getname (el. var)
700
+ end
701
+ end
589
702
590
703
valid_idxs[i] = false
591
704
elements = map (x -> x. var, elements)
@@ -595,7 +708,10 @@ function expand_variable_connections(sys::AbstractSystem)
595
708
end
596
709
end
597
710
eqs = [eqs[valid_idxs]; additional_eqs]
598
- subsystems = map (expand_variable_connections, get_systems (sys))
711
+ subsystems = map (get_systems (sys)) do subsys
712
+ expand_variable_connections (subsys;
713
+ ignored_variables = ignored_systems_for_subsystem (subsys, ignored_variables))
714
+ end
599
715
@set! sys. eqs = eqs
600
716
@set! sys. systems = subsystems
601
717
return sys
0 commit comments