Skip to content

feat: allow toggling namespacing independently of complete #3497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 30, 2025
Merged
12 changes: 12 additions & 0 deletions docs/src/basics/AbstractSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,15 @@ The `AbstractSystem` types allow for specifying default values, for example
into the value maps, where for any repeats the value maps override the default.
In addition, defaults of a higher level in the system override the defaults of
a lower level in the system.

## Namespacing

By default, unsimplified systems will namespace variables accessed via `getproperty`.
Systems created via `@mtkbuild`, or ones passed through `structural_simplify` or
`complete` will not perform this namespacing. However, all of these processes modify
the system in a variety of ways. To toggle namespacing without transforming any other
property of the system, use `toggle_namespacing`.

```@docs
toggle_namespacing
```
2 changes: 1 addition & 1 deletion src/ModelingToolkit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export alg_equations, diff_equations, has_alg_equations, has_diff_equations
export get_alg_eqs, get_diff_eqs, has_alg_eqs, has_diff_eqs

export @variables, @parameters, @independent_variables, @constants, @brownian
export @named, @nonamespace, @namespace, extend, compose, complete
export @named, @nonamespace, @namespace, extend, compose, complete, toggle_namespacing
export debug_system

#export ContinuousClock, Discrete, sampletime, input_timedomain, output_timedomain
Expand Down
38 changes: 36 additions & 2 deletions src/systems/abstractsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,24 @@ function SymbolicIndexingInterface.all_symbols(sys::AbstractSystem)
return syms
end

"""
$(TYPEDSIGNATURES)

Check whether a system is marked as `complete`.
"""
iscomplete(sys::AbstractSystem) = isdefined(sys, :complete) && getfield(sys, :complete)
"""
$(TYPEDSIGNATURES)

Check whether a system performs namespacing.
"""
function does_namespacing(sys::AbstractSystem)
if isdefined(sys, :namespacing)
getfield(sys, :namespacing)
else
!iscomplete(sys)
end
end

"""
$(TYPEDSIGNATURES)
Expand Down Expand Up @@ -798,9 +815,25 @@ function complete(
if isdefined(sys, :initializesystem) && get_initializesystem(sys) !== nothing
@set! sys.initializesystem = complete(get_initializesystem(sys); split)
end
sys = toggle_namespacing(sys, false; safe = true)
isdefined(sys, :complete) ? (@set! sys.complete = true) : sys
end

"""
$(TYPEDSIGNATURES)

Return a new `sys` with namespacing enabled or disabled, depending on `value`. The
keyword argument `safe` denotes whether systems that do not support such a toggle
should error or be ignored.
"""
function toggle_namespacing(sys::AbstractSystem, value::Bool; safe = false)
if !isdefined(sys, :namespacing)
safe && return sys
throw(ArgumentError("The system must define the `namespacing` flag to toggle namespacing"))
end
@set sys.namespacing = value
end

"""
$(TYPEDSIGNATURES)

Expand Down Expand Up @@ -985,13 +1018,14 @@ function Base.propertynames(sys::AbstractSystem; private = false)
end
end

function Base.getproperty(sys::AbstractSystem, name::Symbol; namespace = !iscomplete(sys))
function Base.getproperty(
sys::AbstractSystem, name::Symbol; namespace = does_namespacing(sys))
if has_parent(sys) && (parent = get_parent(sys); parent !== nothing)
return getproperty(parent, name; namespace)
end
wrap(getvar(sys, name; namespace = namespace))
end
function getvar(sys::AbstractSystem, name::Symbol; namespace = !iscomplete(sys))
function getvar(sys::AbstractSystem, name::Symbol; namespace = does_namespacing(sys))
systems = get_systems(sys)
if isdefined(sys, name)
Base.depwarn(
Expand Down
8 changes: 7 additions & 1 deletion src/systems/analysis_points.jl
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,13 @@ already an `AnalysisPoint` or `Symbol`) is simply wrapped in an array. `Symbol`
`AnalysisPoint`s are namespaced with `sys`.
"""
canonicalize_ap(sys::AbstractSystem, ap::Symbol) = [AnalysisPoint(renamespace(sys, ap))]
canonicalize_ap(sys::AbstractSystem, ap::AnalysisPoint) = [ap]
function canonicalize_ap(sys::AbstractSystem, ap::AnalysisPoint)
if does_namespacing(sys)
return [ap]
else
return [renamespace(sys, ap)]
end
end
canonicalize_ap(sys::AbstractSystem, ap) = [ap]
function canonicalize_ap(sys::AbstractSystem, aps::Vector)
mapreduce(Base.Fix1(canonicalize_ap, sys), vcat, aps; init = [])
Expand Down
14 changes: 10 additions & 4 deletions src/systems/diffeqs/odesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,11 @@ struct ODESystem <: AbstractODESystem
"""
substitutions::Any
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand Down Expand Up @@ -207,8 +211,8 @@ struct ODESystem <: AbstractODESystem
connector_type, preface, cevents,
devents, parameter_dependencies, assertions = Dict{BasicSymbolic, String}(),
metadata = nothing, gui_metadata = nothing, is_dde = false,
tstops = [], tearing_state = nothing,
substitutions = nothing, complete = false, index_cache = nothing,
tstops = [], tearing_state = nothing, substitutions = nothing,
namespacing = true, complete = false, index_cache = nothing,
discrete_subsystems = nothing, solved_unknowns = nothing,
split_idxs = nothing, ignored_connections = nothing, parent = nothing;
checks::Union{Bool, Int} = true)
Expand All @@ -218,6 +222,7 @@ struct ODESystem <: AbstractODESystem
check_parameters(ps, iv)
check_equations(deqs, iv)
check_equations(equations(cevents), iv)
check_subsystems(systems)
end
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(dvs, ps, iv)
Expand All @@ -228,7 +233,8 @@ struct ODESystem <: AbstractODESystem
ctrl_jac, Wfact, Wfact_t, name, description, systems, defaults, guesses, torn_matching,
initializesystem, initialization_eqs, schedule, connector_type, preface,
cevents, devents, parameter_dependencies, assertions, metadata,
gui_metadata, is_dde, tstops, tearing_state, substitutions, complete, index_cache,
gui_metadata, is_dde, tstops, tearing_state, substitutions, namespacing,
complete, index_cache,
discrete_subsystems, solved_unknowns, split_idxs, ignored_connections, parent)
end
end
Expand Down
19 changes: 11 additions & 8 deletions src/systems/diffeqs/sdesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ struct SDESystem <: AbstractODESystem
"""
gui_metadata::Union{Nothing, GUIMetadata}
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand All @@ -166,7 +170,7 @@ struct SDESystem <: AbstractODESystem
guesses, initializesystem, initialization_eqs, connector_type,
cevents, devents, parameter_dependencies, assertions = Dict{
BasicSymbolic, Nothing},
metadata = nothing, gui_metadata = nothing,
metadata = nothing, gui_metadata = nothing, namespacing = true,
complete = false, index_cache = nothing, parent = nothing, is_scalar_noise = false,
is_dde = false,
isscheduled = false;
Expand All @@ -184,6 +188,7 @@ struct SDESystem <: AbstractODESystem
if is_scalar_noise && neqs isa AbstractMatrix
throw(ArgumentError("Noise equations ill-formed. Received a matrix of noise equations of size $(size(neqs)), but `is_scalar_noise` was set to `true`. Scalar noise is only compatible with an `AbstractVector` of noise equations."))
end
check_subsystems(systems)
end
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(dvs, ps, iv)
Expand All @@ -192,8 +197,8 @@ struct SDESystem <: AbstractODESystem
new(tag, deqs, neqs, iv, dvs, ps, tspan, var_to_name, ctrls, observed, tgrad, jac,
ctrl_jac, Wfact, Wfact_t, name, description, systems,
defaults, guesses, initializesystem, initialization_eqs, connector_type, cevents,
devents, parameter_dependencies, assertions, metadata, gui_metadata, complete,
index_cache, parent, is_scalar_noise, is_dde, isscheduled)
devents, parameter_dependencies, assertions, metadata, gui_metadata, namespacing,
complete, index_cache, parent, is_scalar_noise, is_dde, isscheduled)
end
end

Expand All @@ -218,7 +223,6 @@ function SDESystem(deqs::AbstractVector{<:Equation}, neqs::AbstractArray, iv, dv
assertions = Dict{BasicSymbolic, String}(),
metadata = nothing,
gui_metadata = nothing,
complete = false,
index_cache = nothing,
parent = nothing,
is_scalar_noise = false,
Expand Down Expand Up @@ -274,7 +278,7 @@ function SDESystem(deqs::AbstractVector{<:Equation}, neqs::AbstractArray, iv, dv
ctrl_jac, Wfact, Wfact_t, name, description, systems, defaults, guesses,
initializesystem, initialization_eqs, connector_type,
cont_callbacks, disc_callbacks, parameter_dependencies, assertions, metadata, gui_metadata,
complete, index_cache, parent, is_scalar_noise, is_dde; checks = checks)
true, false, index_cache, parent, is_scalar_noise, is_dde; checks = checks)
end

function SDESystem(sys::ODESystem, neqs; kwargs...)
Expand Down Expand Up @@ -321,9 +325,8 @@ function SDESystem(eqs::Vector{Equation}, noiseeqs::AbstractArray, iv; kwargs...
throw(ArgumentError("Variable $dv in noise equations is not an unknown of the system."))
end
algevars = setdiff(allunknowns, diffvars)

return SDESystem(eqs, noiseeqs, iv, Iterators.flatten((diffvars, algevars)),
[ps; collect(noiseps)]; kwargs...)
[collect(ps); collect(noiseps)]; kwargs...)
end

function SDESystem(eq::Equation, noiseeqs::AbstractArray, args...; kwargs...)
Expand Down
12 changes: 9 additions & 3 deletions src/systems/discrete_system/discrete_system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ struct DiscreteSystem <: AbstractDiscreteSystem
"""
substitutions::Any
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand All @@ -114,14 +118,15 @@ struct DiscreteSystem <: AbstractDiscreteSystem
observed, name, description, systems, defaults, guesses, initializesystem,
initialization_eqs, preface, connector_type, parameter_dependencies = Equation[],
metadata = nothing, gui_metadata = nothing,
tearing_state = nothing, substitutions = nothing,
tearing_state = nothing, substitutions = nothing, namespacing = true,
complete = false, index_cache = nothing, parent = nothing,
isscheduled = false;
checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(dvs, iv)
check_parameters(ps, iv)
check_subsystems(systems)
end
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(dvs, ps, iv)
Expand All @@ -130,7 +135,8 @@ struct DiscreteSystem <: AbstractDiscreteSystem
new(tag, discreteEqs, iv, dvs, ps, tspan, var_to_name, observed, name, description,
systems, defaults, guesses, initializesystem, initialization_eqs,
preface, connector_type, parameter_dependencies, metadata, gui_metadata,
tearing_state, substitutions, complete, index_cache, parent, isscheduled)
tearing_state, substitutions, namespacing, complete, index_cache, parent,
isscheduled)
end
end

Expand Down
12 changes: 9 additions & 3 deletions src/systems/discrete_system/implicit_discrete_system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ struct ImplicitDiscreteSystem <: AbstractDiscreteSystem
"""
substitutions::Any
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand All @@ -113,14 +117,15 @@ struct ImplicitDiscreteSystem <: AbstractDiscreteSystem
observed, name, description, systems, defaults, guesses, initializesystem,
initialization_eqs, preface, connector_type, parameter_dependencies = Equation[],
metadata = nothing, gui_metadata = nothing,
tearing_state = nothing, substitutions = nothing,
tearing_state = nothing, substitutions = nothing, namespacing = true,
complete = false, index_cache = nothing, parent = nothing,
isscheduled = false;
checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(dvs, iv)
check_parameters(ps, iv)
check_subsystems(systems)
end
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(dvs, ps, iv)
Expand All @@ -129,7 +134,8 @@ struct ImplicitDiscreteSystem <: AbstractDiscreteSystem
new(tag, discreteEqs, iv, dvs, ps, tspan, var_to_name, observed, name, description,
systems, defaults, guesses, initializesystem, initialization_eqs,
preface, connector_type, parameter_dependencies, metadata, gui_metadata,
tearing_state, substitutions, complete, index_cache, parent, isscheduled)
tearing_state, substitutions, namespacing, complete, index_cache, parent,
isscheduled)
end
end

Expand Down
11 changes: 8 additions & 3 deletions src/systems/jumps/jumpsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem
"""
gui_metadata::Union{Nothing, GUIMetadata}
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand All @@ -130,12 +134,13 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem
systems, defaults, guesses, initializesystem, initialization_eqs, connector_type,
cevents, devents,
parameter_dependencies, metadata = nothing, gui_metadata = nothing,
complete = false, index_cache = nothing, isscheduled = false;
namespacing = true, complete = false, index_cache = nothing, isscheduled = false;
checks::Union{Bool, Int} = true) where {U <: ArrayPartition}
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(unknowns, iv)
check_parameters(ps, iv)
check_subsystems(systems)
end
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(unknowns, ps, iv)
Expand All @@ -145,7 +150,7 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem
observed, name, description, systems, defaults, guesses, initializesystem,
initialization_eqs,
connector_type, cevents, devents, parameter_dependencies, metadata,
gui_metadata, complete, index_cache, isscheduled)
gui_metadata, namespacing, complete, index_cache, isscheduled)
end
end
function JumpSystem(tag, ap, iv, states, ps, var_to_name, args...; kwargs...)
Expand Down
11 changes: 8 additions & 3 deletions src/systems/nonlinear/nonlinearsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ struct NonlinearSystem <: AbstractTimeIndependentSystem
"""
substitutions::Any
"""
If a model `sys` is complete, then `sys.x` no longer performs namespacing.
If false, then `sys.x` no longer performs namespacing.
"""
namespacing::Bool
"""
If true, denotes the model will not be modified any further.
"""
complete::Bool
"""
Expand All @@ -112,17 +116,18 @@ struct NonlinearSystem <: AbstractTimeIndependentSystem
tag, eqs, unknowns, ps, var_to_name, observed, jac, name, description,
systems, defaults, guesses, initializesystem, initialization_eqs, connector_type,
parameter_dependencies = Equation[], metadata = nothing, gui_metadata = nothing,
tearing_state = nothing, substitutions = nothing,
tearing_state = nothing, substitutions = nothing, namespacing = true,
complete = false, index_cache = nothing, parent = nothing,
isscheduled = false; checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckUnits) > 0
u = __get_unit_type(unknowns, ps)
check_units(u, eqs)
check_subsystems(systems)
end
new(tag, eqs, unknowns, ps, var_to_name, observed, jac, name, description,
systems, defaults, guesses, initializesystem, initialization_eqs,
connector_type, parameter_dependencies, metadata, gui_metadata, tearing_state,
substitutions, complete, index_cache, parent, isscheduled)
substitutions, namespacing, complete, index_cache, parent, isscheduled)
end
end

Expand Down
Loading
Loading