@@ -1261,18 +1261,18 @@ namespace_parameters(sys::AbstractSystem) = parameters(sys, parameters(sys))
12611261namespace_guesses (sys:: AbstractSystem ) = namespace_expr (guesses (sys), sys)
12621262
12631263"""
1264- $(TYPEDSIGNATURES )
1264+ namespace_equations(sys::AbstractSystem )
12651265
12661266Return `equations(sys)`, namespaced by the name of `sys`.
12671267"""
1268- function namespace_equations (sys:: AbstractSystem , ivs = independent_variables (sys ))
1269- eqs = equations (sys)
1268+ function namespace_equations (sys:: AbstractSystem , visitor = NoVisitor ( ))
1269+ eqs = equations (sys, visitor )
12701270 isempty (eqs) && return eqs
12711271 if eqs === get_eqs (sys)
12721272 eqs = copy (eqs)
12731273 end
12741274 for i in eachindex (eqs)
1275- eqs[i] = namespace_equation (eqs[i], sys; ivs )
1275+ eqs[i] = namespace_equation (eqs[i], sys)
12761276 end
12771277 return eqs
12781278end
@@ -1657,25 +1657,125 @@ end
16571657flatten (sys:: AbstractSystem , args... ) = sys
16581658
16591659"""
1660- $(TYPEDSIGNATURES)
1660+ $TYPEDEF
1661+
1662+ Abstract supertype for functors that can be passed to recursive functions such as
1663+ [`equations`](@ref) to track additional information.
1664+ """
1665+ abstract type AbstractRecursivePropertyVisitor end
1666+
1667+ """
1668+ descend_visitor!(visitor::AbstractRecursivePropertyVisitor, sys::AbstractSystem, f)
1669+
1670+ Descend the `visitor` into system `sys`. Also provide the getter function `f` for the
1671+ property the recursive function handles (e.g. `get_eqs` for `equations`).
1672+ """
1673+ function descend_visitor! end
1674+
1675+ """
1676+ ascend_visitor!(visitor::AbstractRecursivePropertyVisitor, sys::AbstractSystem, f)
1677+
1678+ Ascend the `visitor` from system `sys` into the parent, marking that all its subsystems
1679+ have been explored. Also provide the getter function `f` for the property the recursive
1680+ function handles (e.g. `get_eqs` for `equations`).
1681+ """
1682+ function ascend_visitor! end
1683+
1684+ """
1685+ $TYPEDEF
1686+
1687+ Dummy visitor
1688+ """
1689+ struct NoVisitor <: AbstractRecursivePropertyVisitor end
1690+ descend_visitor! (:: NoVisitor , :: AbstractSystem , _) = nothing
1691+ ascend_visitor! (:: NoVisitor , :: AbstractSystem , _) = nothing
1692+
1693+ """
1694+ $TYPEDEF
1695+
1696+ Visitor that tracks source information
1697+ """
1698+ struct SourceInformationVisitor <: AbstractRecursivePropertyVisitor
1699+ """
1700+ List of names indicating the subsystem containing each value as a path from the root.
1701+ Names are in reverse order (root occurs last).
1702+ """
1703+ sources:: Vector{Vector{Symbol}}
1704+ """
1705+ A stack of indices indicating the index where source entries belonging to each system
1706+ in the call stack start.
1707+ """
1708+ start_positions_stack:: Vector{Int}
1709+ end
1710+
1711+ SourceInformationVisitor () = SourceInformationVisitor (Vector{Symbol}[], Int[])
1712+
1713+ function descend_visitor! (vis:: SourceInformationVisitor , sys:: AbstractSystem , f)
1714+ (; sources, start_positions_stack) = vis
1715+ # The sources for equations in this system start from the next valid index
1716+ start = length (sources) + 1
1717+ push! (start_positions_stack, start)
1718+ # Add source information for the current system
1719+ for _ in f (sys)
1720+ push! (sources, Symbol[])
1721+ end
1722+ end
1723+
1724+ function ascend_visitor! (vis:: SourceInformationVisitor , sys:: AbstractSystem , f)
1725+ (; sources, start_positions_stack) = vis
1726+ # Get the start position for `sys`. We know we've explored all subsystems of `sys`.
1727+ cur_start = pop! (start_positions_stack)
1728+ # Since the search is DFS, all entries in `sources` from `cur_start` till the
1729+ # end are inside `sys`, so add the name to them.
1730+ name = nameof (sys)
1731+ for i in cur_start: lastindex (sources)
1732+ push! (sources[i], name)
1733+ end
1734+ end
1735+
1736+ """
1737+ equations(sys::AbstractSystem)
16611738
16621739Get the flattened equations of the system `sys` and its subsystems.
16631740It may include some abbreviations and aliases of observables.
16641741It is often the most useful way to inspect the equations of a system.
16651742
16661743See also [`full_equations`](@ref) and [`ModelingToolkitBase.get_eqs`](@ref).
16671744"""
1668- function equations (sys:: AbstractSystem )
1745+ function equations (sys:: AbstractSystem , visitor :: AbstractRecursivePropertyVisitor = NoVisitor () )
16691746 eqs = get_eqs (sys)
16701747 systems = get_systems (sys)
1671- isempty (systems) && return eqs
1748+ descend_visitor! (visitor, sys, get_eqs)
1749+ if isempty (systems)
1750+ ascend_visitor! (visitor, sys, get_eqs)
1751+ return eqs
1752+ end
16721753 eqs = copy (eqs)
16731754 for subsys in systems
1674- append! (eqs, namespace_equations (subsys))
1755+ append! (eqs, namespace_equations (subsys, visitor ))
16751756 end
1757+ ascend_visitor! (visitor, sys, get_eqs)
16761758 return eqs
16771759end
16781760
1761+ function equations_source (sys:: AbstractSystem )
1762+ source = Vector{Symbol}[]
1763+ for _ in eachindex (get_eqs (sys))
1764+ push! (source, Symbol[])
1765+ end
1766+ systems = get_systems (sys)
1767+ isempty (systems) && return source
1768+
1769+ for subsys in systems
1770+ name = nameof (subsys)
1771+ sub_sources = equations_source (subsys)
1772+ for src in sub_sources
1773+ push! (src, name)
1774+ end
1775+ append! (source, name)
1776+ end
1777+ end
1778+
16791779"""
16801780 equations_toplevel(sys::AbstractSystem)
16811781
0 commit comments