@@ -717,6 +717,22 @@ function add_initialization_parameters(sys::AbstractSystem)
717
717
return sys
718
718
end
719
719
720
+ """
721
+ Returns true if the parameter `p` is of the form `Initial(x)`.
722
+ """
723
+ function isinitial (p)
724
+ p = unwrap (p)
725
+ if iscall (p)
726
+ operation (p) isa Initial && return true
727
+ if operation (p) === getindex
728
+ operation (arguments (p)[1 ]) isa Initial && return true
729
+ end
730
+ else
731
+ return false
732
+ end
733
+ return false
734
+ end
735
+
720
736
"""
721
737
$(TYPEDSIGNATURES)
722
738
@@ -757,38 +773,21 @@ function complete(sys::AbstractSystem; split = true, flatten = true)
757
773
if ! isempty (all_ps)
758
774
# reorder parameters by portions
759
775
ps_split = reorder_parameters (sys, all_ps)
776
+ # if there are tunables, they will all be in `ps_split[1]`
777
+ # and the arrays will have been scalarized
778
+ ordered_ps = eltype (all_ps)[]
760
779
# if there are no tunables, vcat them
761
- if isempty (get_index_cache (sys). tunable_idx)
762
- ordered_ps = reduce (vcat, ps_split)
763
- else
764
- # if there are tunables, they will all be in `ps_split[1]`
765
- # and the arrays will have been scalarized
766
- ordered_ps = eltype (all_ps)[]
767
- i = 1
768
- # go through all the tunables
769
- while i <= length (ps_split[1 ])
770
- sym = ps_split[1 ][i]
771
- # if the sym is not a scalarized array symbolic OR it was already scalarized,
772
- # just push it as-is
773
- if ! iscall (sym) || operation (sym) != getindex ||
774
- any (isequal (sym), all_ps)
775
- push! (ordered_ps, sym)
776
- i += 1
777
- continue
778
- end
779
- # the next `length(sym)` symbols should be scalarized versions of the same
780
- # array symbolic
781
- if ! allequal (first (arguments (x))
782
- for x in view (ps_split[1 ], i: (i + length (sym) - 1 )))
783
- error (" This should not be possible. Please open an issue in ModelingToolkit.jl with an MWE and stacktrace." )
784
- end
785
- arrsym = first (arguments (sym))
786
- push! (ordered_ps, arrsym)
787
- i += length (arrsym)
788
- end
789
- ordered_ps = vcat (
790
- ordered_ps, reduce (vcat, ps_split[2 : end ]; init = eltype (ordered_ps)[]))
780
+ if ! isempty (get_index_cache (sys). tunable_idx)
781
+ unflatten_parameters! (ordered_ps, ps_split[1 ], all_ps)
782
+ ps_split = Base. tail (ps_split)
783
+ end
784
+ # unflatten initial parameters
785
+ if ! isempty (get_index_cache (sys). initials_idx)
786
+ unflatten_parameters! (ordered_ps, ps_split[1 ], all_ps)
787
+ ps_split = Base. tail (ps_split)
791
788
end
789
+ ordered_ps = vcat (
790
+ ordered_ps, reduce (vcat, ps_split; init = eltype (ordered_ps)[]))
792
791
@set! sys. ps = ordered_ps
793
792
end
794
793
elseif has_index_cache (sys)
@@ -800,6 +799,39 @@ function complete(sys::AbstractSystem; split = true, flatten = true)
800
799
isdefined (sys, :complete ) ? (@set! sys. complete = true ) : sys
801
800
end
802
801
802
+ """
803
+ $(TYPEDSIGNATURES)
804
+
805
+ Given a flattened array of parameters `params` and a collection of all (unscalarized)
806
+ parameters in the system `all_ps`, unscalarize the elements in `params` and append
807
+ to `buffer` in the same order as they are present in `params`. Effectively, if
808
+ `params = [p[1], p[2], p[3], q]` then this is equivalent to `push!(buffer, p, q)`.
809
+ """
810
+ function unflatten_parameters! (buffer, params, all_ps)
811
+ i = 1
812
+ # go through all the tunables
813
+ while i <= length (params)
814
+ sym = params[i]
815
+ # if the sym is not a scalarized array symbolic OR it was already scalarized,
816
+ # just push it as-is
817
+ if ! iscall (sym) || operation (sym) != getindex ||
818
+ any (isequal (sym), all_ps)
819
+ push! (buffer, sym)
820
+ i += 1
821
+ continue
822
+ end
823
+ # the next `length(sym)` symbols should be scalarized versions of the same
824
+ # array symbolic
825
+ if ! allequal (first (arguments (x))
826
+ for x in view (params, i: (i + length (sym) - 1 )))
827
+ error (" This should not be possible. Please open an issue in ModelingToolkit.jl with an MWE and stacktrace." )
828
+ end
829
+ arrsym = first (arguments (sym))
830
+ push! (buffer, arrsym)
831
+ i += length (arrsym)
832
+ end
833
+ end
834
+
803
835
for prop in [:eqs
804
836
:tag
805
837
:noiseeqs
@@ -846,6 +878,7 @@ for prop in [:eqs
846
878
:assertions
847
879
:solved_unknowns
848
880
:split_idxs
881
+ :ignored_connections
849
882
:parent
850
883
:is_dde
851
884
:tstops
@@ -1362,6 +1395,75 @@ function assertions(sys::AbstractSystem)
1362
1395
return merge (asserts, namespaced_asserts)
1363
1396
end
1364
1397
1398
+ const HierarchyVariableT = Vector{Union{BasicSymbolic, Symbol}}
1399
+ const HierarchySystemT = Vector{Union{AbstractSystem, Symbol}}
1400
+ """
1401
+ The type returned from `as_hierarchy`.
1402
+ """
1403
+ const HierarchyT = Union{HierarchyVariableT, HierarchySystemT}
1404
+
1405
+ """
1406
+ $(TYPEDSIGNATURES)
1407
+
1408
+ The inverse operation of `as_hierarchy`.
1409
+ """
1410
+ function from_hierarchy (hierarchy:: HierarchyT )
1411
+ namefn = hierarchy[1 ] isa AbstractSystem ? nameof : getname
1412
+ foldl (@view hierarchy[2 : end ]; init = hierarchy[1 ]) do sys, name
1413
+ rename (sys, Symbol (name, NAMESPACE_SEPARATOR, namefn (sys)))
1414
+ end
1415
+ end
1416
+
1417
+ """
1418
+ $(TYPEDSIGNATURES)
1419
+
1420
+ Represent a namespaced system (or variable) `sys` as a hierarchy. Return a vector, where
1421
+ the first element is the unnamespaced system (variable) and subsequent elements are
1422
+ `Symbol`s representing the parents of the unnamespaced system (variable) in order from
1423
+ inner to outer.
1424
+ """
1425
+ function as_hierarchy (sys:: Union{AbstractSystem, BasicSymbolic} ):: HierarchyT
1426
+ namefn = sys isa AbstractSystem ? nameof : getname
1427
+ # get the hierarchy
1428
+ hierarchy = namespace_hierarchy (namefn (sys))
1429
+ # rename the system with unnamespaced name
1430
+ newsys = rename (sys, hierarchy[end ])
1431
+ # and remove it from the list
1432
+ pop! (hierarchy)
1433
+ # reverse it to go from inner to outer
1434
+ reverse! (hierarchy)
1435
+ # concatenate
1436
+ T = sys isa AbstractSystem ? AbstractSystem : BasicSymbolic
1437
+ return Union{Symbol, T}[newsys; hierarchy]
1438
+ end
1439
+
1440
+ """
1441
+ $(TYPEDSIGNATURES)
1442
+
1443
+ Get the connections to ignore for `sys` and its subsystems. The returned value is a
1444
+ `Tuple` similar in structure to the `ignored_connections` field. Each system (variable)
1445
+ in the first (second) element of the tuple is also passed through `as_hierarchy`.
1446
+ """
1447
+ function ignored_connections (sys:: AbstractSystem )
1448
+ has_ignored_connections (sys) || return (HierarchySystemT[], HierarchyVariableT[])
1449
+
1450
+ ics = get_ignored_connections (sys)
1451
+ if ics === nothing
1452
+ ics = (HierarchySystemT[], HierarchyVariableT[])
1453
+ end
1454
+ # turn into hierarchies
1455
+ ics = (map (as_hierarchy, ics[1 ]), map (as_hierarchy, ics[2 ]))
1456
+ systems = get_systems (sys)
1457
+ # for each subsystem, get its ignored connections, add the name of the subsystem
1458
+ # to the hierarchy and concatenate corresponding buffers of the result
1459
+ result = mapreduce (Broadcast. BroadcastFunction (vcat), systems; init = ics) do subsys
1460
+ sub_ics = ignored_connections (subsys)
1461
+ (map (Base. Fix2 (push!, nameof (subsys)), sub_ics[1 ]),
1462
+ map (Base. Fix2 (push!, nameof (subsys)), sub_ics[2 ]))
1463
+ end
1464
+ return (Vector {HierarchySystemT} (result[1 ]), Vector {HierarchyVariableT} (result[2 ]))
1465
+ end
1466
+
1365
1467
"""
1366
1468
$(TYPEDSIGNATURES)
1367
1469
0 commit comments