@@ -942,3 +942,143 @@ function convert_system_indepvar(sys::System, t; name = nameof(sys))
942942 @set! sys. var_to_name = var_to_name
943943 return sys
944944end
945+
946+ """
947+ $(TYPEDSIGNATURES)
948+
949+ Shorthand for `respecialize(sys, []; all = true)`
950+ """
951+ respecialize (sys:: AbstractSystem ) = respecialize (sys, []; all = true )
952+
953+ """
954+ $(TYPEDSIGNATURES)
955+
956+ Specialize nonnumeric parameters in `sys` by changing their symtype to a concrete type.
957+ `mapping` is an iterable, where each element can be a parameter or a pair mapping a parameter
958+ to a value. If the element is a parameter, it must have a default. Each specified parameter
959+ is updated to have the symtype of the value associated with it (either in `mapping` or in
960+ the defaults). This operation can only be performed on nonnumeric, non-array parameters. The
961+ defaults of respecialized parameters are set to the associated values.
962+
963+ This operation can only be performed on `complete`d systems.
964+
965+ # Keyword arguments
966+
967+ - `all`: Specialize all nonnumeric parameters in the system. This will error if any such
968+ parameter does not have a default.
969+ """
970+ function respecialize (sys:: AbstractSystem , mapping; all = false )
971+ if ! iscomplete (sys)
972+ error ("""
973+ This operation can only be performed on completed systems. Use `complete(sys)` or
974+ `mtkcompile(sys)`.
975+ """ )
976+ end
977+ if ! is_split (sys)
978+ error ("""
979+ This operation can only be performed on split systems. Use `complete(sys)` or
980+ `mtkcompile(sys)` with the `split = true` keyword argument.
981+ """ )
982+ end
983+
984+ new_ps = copy (get_ps (sys))
985+ @set! sys. ps = new_ps
986+
987+ extras = []
988+ if all
989+ for x in filter (! is_variable_numeric, get_ps (sys))
990+ if any (y -> isequal (x, y) || y isa Pair && isequal (x, y[1 ]), mapping) ||
991+ symbolic_type (x) === ArraySymbolic () ||
992+ iscall (x) && operation (x) === getindex
993+ continue
994+ end
995+ push! (extras, x)
996+ end
997+ end
998+ ps_to_specialize = Iterators. flatten ((extras, mapping))
999+
1000+ defs = copy (defaults (sys))
1001+ @set! sys. defaults = defs
1002+ final_defs = copy (defs)
1003+ evaluate_varmap! (final_defs, ps_to_specialize)
1004+
1005+ subrules = Dict ()
1006+
1007+ for element in ps_to_specialize
1008+ if element isa Pair
1009+ k, v = element
1010+ else
1011+ k = element
1012+ v = get (final_defs, k, nothing )
1013+ @assert v != = nothing """
1014+ Parameter $k needs an associated value to be respecialized.
1015+ """
1016+ @assert symbolic_type (v) == NotSymbolic () && ! is_array_of_symbolics (v) """
1017+ Parameter $k needs an associated value to be respecialized. Found symbolic \
1018+ default $v .
1019+ """
1020+ end
1021+
1022+ k = unwrap (k)
1023+ T = typeof (v)
1024+
1025+ @assert ! is_variable_numeric (k) """
1026+ Numeric types cannot be respecialized - tried to respecialize $k .
1027+ """
1028+ @assert symbolic_type (k) != = ArraySymbolic () """
1029+ Cannot respecialize array symbolics - tried to respecialize $k .
1030+ """
1031+ @assert ! iscall (k) || operation (k) != = getindex """
1032+ Cannot respecialized scalarized array variables - tried to respecialize $k .
1033+ """
1034+ idx = findfirst (isequal (k), get_ps (sys))
1035+ @assert idx != = nothing """
1036+ Parameter $k does not exist in the system.
1037+ """
1038+
1039+ if iscall (k)
1040+ op = operation (k)
1041+ args = arguments (k)
1042+ new_p = SymbolicUtils. term (op, args... ; type = T)
1043+ else
1044+ new_p = SymbolicUtils. Sym {T} (getname (k))
1045+ end
1046+
1047+ get_ps (sys)[idx] = new_p
1048+ defaults (sys)[new_p] = v
1049+ subrules[unwrap (k)] = unwrap (new_p)
1050+ end
1051+
1052+ substituter = Base. Fix2 (fast_substitute, subrules)
1053+ @set! sys. eqs = map (substituter, get_eqs (sys))
1054+ @set! sys. observed = map (substituter, get_observed (sys))
1055+ @set! sys. initialization_eqs = map (substituter, get_initialization_eqs (sys))
1056+ if get_noise_eqs (sys) != = nothing
1057+ @set! sys. noise_eqs = map (substituter, get_noise_eqs (sys))
1058+ end
1059+ @set! sys. assertions = Dict ([substituter (k) => v for (k, v) in assertions (sys)])
1060+ @set! sys. parameter_dependencies = map (substituter, get_parameter_dependencies (sys))
1061+ @set! sys. defaults = Dict ([substituter (k) => substituter (v) for (k, v) in defaults (sys)])
1062+ @set! sys. guesses = Dict ([k => substituter (v) for (k, v) in guesses (sys)])
1063+ @set! sys. continuous_events = map (get_continuous_events (sys)) do cev
1064+ SymbolicContinuousCallback (
1065+ map (substituter, cev. conditions), substituter (cev. affect),
1066+ substituter (cev. affect_neg), substituter (cev. initialize),
1067+ substituter (cev. finalize), cev. rootfind,
1068+ cev. reinitializealg, cev. zero_crossing_id)
1069+ end
1070+ @set! sys. discrete_events = map (get_discrete_events (sys)) do dev
1071+ SymbolicDiscreteCallback (map (substituter, dev. conditions), substituter (dev. affect),
1072+ substituter (dev. initialize), substituter (dev. finalize), dev. reinitializealg)
1073+ end
1074+ if get_schedule (sys) != = nothing
1075+ sched = get_schedule (sys)
1076+ @set! sys. schedule = Schedule (
1077+ sched. var_sccs, AnyDict (k => substituter (v) for (k, v) in sched. dummy_sub))
1078+ end
1079+ @set! sys. constraints = map (substituter, get_constraints (sys))
1080+ @set! sys. tstops = map (substituter, get_tstops (sys))
1081+ @set! sys. costs = Vector {Union{Real, BasicSymbolic}} (map (substituter, get_costs (sys)))
1082+ sys = complete (sys; split = is_split (sys))
1083+ return sys
1084+ end
0 commit comments