@@ -706,3 +706,135 @@ function convert_system_indepvar(sys::System, t; name = nameof(sys))
706706 @set! sys. var_to_name = var_to_name
707707 return sys
708708end
709+
710+ """
711+ $(TYPEDSIGNATURES)
712+
713+ Shorthand for `respecialize(sys, []; all = true)`
714+ """
715+ respecialize (sys:: AbstractSystem ) = respecialize (sys, []; all = true )
716+
717+ """
718+ $(TYPEDSIGNATURES)
719+
720+ Specialize nonnumeric parameters in `sys` by changing their symtype to a concrete type.
721+ `mapping` is an iterable, where each element can be a parameter or a pair mapping a parameter
722+ to a value. If the element is a parameter, it must have a default. Each specified parameter
723+ is updated to have the symtype of the value associated with it (either in `mapping` or in
724+ the defaults). This operation can only be performed on nonnumeric, non-array parameters. The
725+ defaults of respecialized parameters are set to the associated values.
726+
727+ This operation can only be performed on `complete`d systems.
728+
729+ # Keyword arguments
730+
731+ - `all`: Specialize all nonnumeric parameters in the system. This will error if any such
732+ parameter does not have a default.
733+ """
734+ function respecialize (sys:: AbstractSystem , mapping; all = false )
735+ if ! iscomplete (sys)
736+ error ("""
737+ This operation can only be performed on completed systems. Use `complete(sys)` or
738+ `mtkcompile(sys)`.
739+ """ )
740+ end
741+ if ! is_split (sys)
742+ error ("""
743+ This operation can only be performed on split systems. Use `complete(sys)` or
744+ `mtkcompile(sys)` with the `split = true` keyword argument.
745+ """ )
746+ end
747+
748+ new_ps = copy (get_ps (sys))
749+ @set! sys. ps = new_ps
750+
751+ extras = []
752+ if all
753+ for x in filter (! is_variable_numeric, get_ps (sys))
754+ if any (y -> isequal (x, y) || y isa Pair && isequal (x, y[1 ]), mapping) ||
755+ symbolic_type (x) === ArraySymbolic () ||
756+ iscall (x) && operation (x) === getindex
757+ continue
758+ end
759+ push! (extras, x)
760+ end
761+ end
762+
763+ defs = copy (defaults (sys))
764+ @set! sys. defaults = defs
765+
766+ subrules = Dict ()
767+
768+ for element in Iterators. flatten ((extras, mapping))
769+ if element isa Pair
770+ k, v = element
771+ else
772+ k = element
773+ v = get (defs, k, nothing )
774+ @assert v != = nothing """
775+ Parameter $k needs an associated value to be respecialized.
776+ """
777+ end
778+
779+ k = unwrap (k)
780+ T = typeof (v)
781+
782+ @assert ! is_variable_numeric (k) """
783+ Numeric types cannot be respecialized - tried to respecialize $k .
784+ """
785+ @assert symbolic_type (k) != = ArraySymbolic () """
786+ Cannot respecialize array symbolics - tried to respecialize $k .
787+ """
788+ @assert ! iscall (k) || operation (k) != = getindex """
789+ Cannot respecialized scalarized array variables - tried to respecialize $k .
790+ """
791+ idx = findfirst (isequal (k), get_ps (sys))
792+ @assert idx != = nothing """
793+ Parameter $k does not exist in the system.
794+ """
795+
796+ if iscall (k)
797+ op = operation (k)
798+ args = arguments (k)
799+ new_p = SymbolicUtils. term (op, args... ; type = T)
800+ else
801+ new_p = SymbolicUtils. Sym {T} (getname (k))
802+ end
803+
804+ get_ps (sys)[idx] = new_p
805+ defaults (sys)[new_p] = v
806+ subrules[unwrap (k)] = unwrap (new_p)
807+ end
808+
809+ substituter = Base. Fix2 (fast_substitute, subrules)
810+ @set! sys. eqs = map (substituter, get_eqs (sys))
811+ @set! sys. initialization_eqs = map (substituter, get_initialization_eqs (sys))
812+ if get_noise_eqs (sys) != = nothing
813+ @set! sys. noise_eqs = map (substituter, get_noise_eqs (sys))
814+ end
815+ @set! sys. assertions = Dict ([substituter (k) => v for (k, v) in assertions (sys)])
816+ @set! sys. parameter_dependencies = map (substituter, get_parameter_dependencies (sys))
817+ @set! sys. defaults = Dict ([k => substituter (v) for (k, v) in defaults (sys)])
818+ @set! sys. guesses = Dict ([k => substituter (v) for (k, v) in guesses (sys)])
819+ @set! sys. continuous_events = map (get_continuous_events (sys)) do cev
820+ SymbolicContinuousCallback (
821+ map (substituter, cev. conditions), substituter (cev. affect),
822+ substituter (cev. affect_neg), substituter (cev. initialize),
823+ substituter (cev. finalize), cev. rootfind,
824+ cev. reinitializealg, cev. zero_crossing_id)
825+ end
826+ @set! sys. discrete_events = map (get_discrete_events (sys)) do dev
827+ SymbolicDiscreteCallback (map (substituter, dev. conditions), substituter (dev. affect),
828+ substituter (dev. initialize), substituter (dev. finalize), dev. reinitializealg)
829+ end
830+ if get_schedule (sys) != = nothing
831+ sched = get_schedule (sys)
832+ @set! sys. schedule = Schedule (
833+ sched. var_sccs, AnyDict (k => substituter (v) for (k, v) in sched. dummy_sub))
834+ end
835+ @set! sys. constraints = map (substituter, get_constraints (sys))
836+ @set! sys. tstops = map (substituter, get_tstops (sys))
837+ @set! sys. costs = map (substituter, get_costs (sys))
838+ sys = complete (sys; split = is_split (sys))
839+ return sys
840+ end
0 commit comments