Skip to content

Commit ce72751

Browse files
fix: only ignore systems in connection sets involving ignored analysis point
1 parent fdcac6f commit ce72751

File tree

2 files changed

+110
-48
lines changed

2 files changed

+110
-48
lines changed

src/systems/analysis_points.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -417,20 +417,20 @@ function with_analysis_point_ignored(sys::AbstractSystem, ap::AnalysisPoint)
417417
has_ignored_connections(sys) || return sys
418418
ignored = get_ignored_connections(sys)
419419
if ignored === nothing
420-
ignored = (ODESystem[], BasicSymbolic[])
420+
ignored = (IgnoredAnalysisPoint[], IgnoredAnalysisPoint[])
421421
else
422422
ignored = copy.(ignored)
423423
end
424424
if ap.outputs === nothing
425425
error("Empty analysis point")
426426
end
427-
for x in ap.outputs
428-
if x isa ODESystem
429-
push!(ignored[1], x)
430-
else
431-
push!(ignored[2], unwrap(x))
432-
end
427+
428+
if ap.input isa AbstractSystem && all(x -> x isa AbstractSystem, ap.outputs)
429+
push!(ignored[1], IgnoredAnalysisPoint(ap.input, ap.outputs))
430+
else
431+
push!(ignored[2], IgnoredAnalysisPoint(ap.input, ap.outputs))
433432
end
433+
434434
return @set sys.ignored_connections = ignored
435435
end
436436

src/systems/connectors.jl

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,12 @@ namespaced by `namespace`.
328328
`ignored_connects[1]`, purely to avoid unnecessary recomputation.
329329
"""
330330
function connection2set!(connectionsets, namespace, ss, isouter;
331-
ignored_connects = (HierarchySystemT[], HierarchyVariableT[]),
332-
namespaced_ignored_systems = ODESystem[])
333-
ignored_systems, ignored_variables = ignored_connects
331+
ignored_systems = HierarchySystemT[], ignored_variables = HierarchyVariableT[])
332+
ns_ignored_systems = from_hierarchy.(ignored_systems)
333+
ns_ignored_variables = from_hierarchy.(ignored_variables)
334334
# ignore specified systems
335335
ss = filter(ss) do s
336-
all(namespaced_ignored_systems) do igsys
337-
nameof(igsys) != nameof(s)
338-
end
336+
!any(x -> nameof(x) == nameof(s), ns_ignored_systems)
339337
end
340338
# `ignored_variables` for each `s` in `ss`
341339
corresponding_ignored_variables = map(
@@ -434,15 +432,95 @@ function generate_connection_set(
434432
connectionsets = ConnectionSet[]
435433
domain_csets = ConnectionSet[]
436434
sys = generate_connection_set!(
437-
connectionsets, domain_csets, sys, find, replace, scalarize, nothing,
438-
# include systems to be ignored
439-
ignored_connections(sys))
435+
connectionsets, domain_csets, sys, find, replace, scalarize, nothing, ignored_connections(sys))
440436
csets = merge(connectionsets)
441437
domain_csets = merge([csets; domain_csets], true)
442438

443439
sys, (csets, domain_csets)
444440
end
445441

442+
"""
443+
$(TYPEDSIGNATURES)
444+
445+
For a list of `systems` in a connect equation, return the subset of it to ignore (as a
446+
list of hierarchical systems) based on `ignored_system_aps`, the analysis points to be
447+
ignored. All analysis points in `ignored_system_aps` must contain systems (connectors)
448+
as their input/outputs.
449+
"""
450+
function systems_to_ignore(ignored_system_aps::Vector{HierarchyAnalysisPointT},
451+
systems::Union{Vector{<:AbstractSystem}, Tuple{Vararg{<:AbstractSystem}}})
452+
to_ignore = HierarchySystemT[]
453+
for ap in ignored_system_aps
454+
# if `systems` contains the input of the AP, ignore any outputs of the AP present in it.
455+
isys_hierarchy = HierarchySystemT([ap[1].input; @view ap[2:end]])
456+
isys = from_hierarchy(isys_hierarchy)
457+
any(x -> nameof(x) == nameof(isys), systems) || continue
458+
459+
for outsys in ap[1].outputs
460+
osys_hierarchy = HierarchySystemT([outsys; @view ap[2:end]])
461+
osys = from_hierarchy(osys_hierarchy)
462+
any(x -> nameof(x) == nameof(osys), systems) || continue
463+
push!(to_ignore, HierarchySystemT(osys_hierarchy))
464+
end
465+
end
466+
467+
return to_ignore
468+
end
469+
470+
"""
471+
$(TYPEDSIGNATURES)
472+
473+
For a list of `systems` in a connect equation, return the subset of their variables to
474+
ignore (as a list of hierarchical variables) based on `ignored_system_aps`, the analysis
475+
points to be ignored. All analysis points in `ignored_system_aps` must contain variables
476+
as their input/outputs.
477+
"""
478+
function variables_to_ignore(ignored_variable_aps::Vector{HierarchyAnalysisPointT},
479+
systems::Union{Vector{<:AbstractSystem}, Tuple{Vararg{<:AbstractSystem}}})
480+
to_ignore = HierarchyVariableT[]
481+
for ap in ignored_variable_aps
482+
ivar_hierarchy = HierarchyVariableT([ap[1].input; @view ap[2:end]])
483+
ivar = from_hierarchy(ivar_hierarchy)
484+
any(x -> any(isequal(ivar), renamespace.((x,), unknowns(x))), systems) || continue
485+
486+
for outvar in ap[1].outputs
487+
ovar_hierarchy = HierarchyVariableT([as_hierarchy(outvar); @view ap[2:end]])
488+
ovar = from_hierarchy(ovar_hierarchy)
489+
any(x -> any(isequal(ovar), renamespace.((x,), unknowns(x))), systems) ||
490+
continue
491+
push!(to_ignore, HierarchyVariableT(ovar_hierarchy))
492+
end
493+
end
494+
return to_ignore
495+
end
496+
497+
"""
498+
$(TYPEDSIGNATURES)
499+
500+
For a list of variables `vars` in a connect equation, return the subset of them ignore
501+
(as a list of symbolic variables) based on `ignored_system_aps`, the analysis points to
502+
be ignored. All analysis points in `ignored_system_aps` must contain variables as their
503+
input/outputs.
504+
"""
505+
function variables_to_ignore(ignored_variable_aps::Vector{HierarchyAnalysisPointT},
506+
vars::Union{Vector{<:BasicSymbolic}, Tuple{Vararg{<:BasicSymbolic}}})
507+
to_ignore = eltype(vars)[]
508+
for ap in ignored_variable_aps
509+
ivar_hierarchy = HierarchyVariableT([ap[1].input; @view ap[2:end]])
510+
ivar = from_hierarchy(ivar_hierarchy)
511+
any(isequal(ivar), vars) || continue
512+
513+
for outvar in ap[1].outputs
514+
ovar_hierarchy = HierarchyVariableT([outvar; @view ap[2:end]])
515+
ovar = from_hierarchy(ovar_hierarchy)
516+
any(isequal(ovar), vars) || continue
517+
push!(to_ignore, ovar)
518+
end
519+
end
520+
521+
return to_ignore
522+
end
523+
446524
"""
447525
$(TYPEDSIGNATURES)
448526
@@ -456,26 +534,12 @@ Generate connection sets from `connect` equations.
456534
- `sys` is the system whose equations are to be searched.
457535
- `namespace` is a system representing the namespace in which `sys` exists, or `nothing`
458536
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.
463537
"""
464538
function generate_connection_set!(connectionsets, domain_csets,
465539
sys::AbstractSystem, find, replace, scalarize, namespace = nothing,
466-
ignored_connects = (HierarchySystemT[], HierarchyVariableT[]))
540+
ignored_connects = (HierarchyAnalysisPointT[], HierarchyAnalysisPointT[]))
467541
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
542+
ignored_system_aps, ignored_variable_aps = ignored_connects
479543

480544
isouter = generate_isouter(sys)
481545
eqs′ = get_eqs(sys)
@@ -501,8 +565,12 @@ function generate_connection_set!(connectionsets, domain_csets,
501565
neweq isa AbstractArray ? append!(eqs, neweq) : push!(eqs, neweq)
502566
else
503567
if lhs isa Connection && get_systems(lhs) === :domain
504-
connection2set!(domain_csets, namespace, get_systems(rhs), isouter;
505-
ignored_connects, namespaced_ignored_systems)
568+
connected_systems = get_systems(rhs)
569+
connection2set!(domain_csets, namespace, connected_systems, isouter;
570+
ignored_systems = systems_to_ignore(
571+
ignored_system_aps, connected_systems),
572+
ignored_variables = variables_to_ignore(
573+
ignored_variable_aps, connected_systems))
506574
elseif isconnection(rhs)
507575
push!(cts, get_systems(rhs))
508576
else
@@ -519,22 +587,19 @@ function generate_connection_set!(connectionsets, domain_csets,
519587
# all connectors are eventually inside connectors.
520588
T = ConnectionElement
521589
# only generate connection sets for systems that are not ignored
522-
for s in filtered_subsys
590+
for s in subsys
523591
isconnector(s) || continue
524592
is_domain_connector(s) && continue
525-
_ignored_variables = ignored_systems_for_subsystem(s, ignored_variables)
526-
_namespaced_ignored_variables = from_hierarchy.(_ignored_variables)
527593
for v in unknowns(s)
528594
Flow === get_connection_type(v) || continue
529-
# ignore specified variables
530-
any(isequal(v), _namespaced_ignored_variables) && continue
531595
push!(connectionsets, ConnectionSet([T(LazyNamespace(namespace, s), v, false)]))
532596
end
533597
end
534598

535599
for ct in cts
536600
connection2set!(connectionsets, namespace, ct, isouter;
537-
ignored_connects, namespaced_ignored_systems)
601+
ignored_systems = systems_to_ignore(ignored_system_aps, ct),
602+
ignored_variables = variables_to_ignore(ignored_variable_aps, ct))
538603
end
539604

540605
# pre order traversal
@@ -558,14 +623,15 @@ ignored by `generate_connection_set!` (`expand_variable_connections`), filter
558623
their hierarchy to not include `subsys`.
559624
"""
560625
function ignored_systems_for_subsystem(
561-
subsys::AbstractSystem, ignored_systems::Vector{<:HierarchyT})
626+
subsys::AbstractSystem, ignored_systems::Vector{<:Union{
627+
HierarchyT, HierarchyAnalysisPointT}})
562628
result = eltype(ignored_systems)[]
563629
# in case `subsys` is namespaced, get its hierarchy and compare suffixes
564630
# instead of the just the last element
565631
suffix = reverse!(namespace_hierarchy(nameof(subsys)))
566632
N = length(suffix)
567633
for igsys in ignored_systems
568-
if igsys[(end - N + 1):end] == suffix
634+
if length(igsys) > N && igsys[(end - N + 1):end] == suffix
569635
push!(result, copy(igsys))
570636
for i in 1:N
571637
pop!(result[end])
@@ -684,7 +750,6 @@ function expand_variable_connections(sys::AbstractSystem; ignored_variables = no
684750
if ignored_variables === nothing
685751
ignored_variables = ignored_connections(sys)[2]
686752
end
687-
namespaced_ignored = from_hierarchy.(ignored_variables)
688753
eqs = copy(get_eqs(sys))
689754
valid_idxs = trues(length(eqs))
690755
additional_eqs = Equation[]
@@ -694,14 +759,11 @@ function expand_variable_connections(sys::AbstractSystem; ignored_variables = no
694759
connection = eq.rhs
695760
elements = get_systems(connection)
696761
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
702762

703763
valid_idxs[i] = false
704764
elements = map(x -> x.var, elements)
765+
to_ignore = variables_to_ignore(ignored_variables, elements)
766+
elements = setdiff(elements, to_ignore)
705767
outvar = first(elements)
706768
for invar in Iterators.drop(elements, 1)
707769
push!(additional_eqs, outvar ~ invar)

0 commit comments

Comments
 (0)