Open baggepinnen opened 1 year ago
I also encountered the same situation. I needed to replace the type of a component in a model. For this , Modelica has two keywords that can be used together: replaceable, redeclare.
ModelicaStandardLibrary use extensivly the keywords: replaceable , redeclare, are they nessary forModelingToolkit?
redeclare can also be used alone, like:
class Parent
Real x;
end Parent;
class Child extends Parent
redeclare Real x(start=1.0);
end Child;
@ChrisRackauckas @YingboMa , ... , Thanks for your great work, I am a new user of Julia and ModelingToolkit.
I also want this. Here is a hacky solution I have cooked up:
using ModelingToolkit
using ModelingToolkit: t_nounits as t
# transform a system with a function f while preserving the hierarchical structure of its subsystems
# f must modify fields local to each system, and not its subsystems (e.g. get_eqs() instead of equations())!
function transform(f::Function, sys::ODESystem; fullname=string(sys.name), kwargs...)
subs = [transform(f, sub; fullname = fullname * "₊" * string(sub.name)) for sub in sys.systems]
sys = f(sys, fullname)
return compose(sys, subs; kwargs...)
end
# return a local copy of a system (excluding fields that are part of its subsystems)
function identity(sys)
eqs = ModelingToolkit.get_eqs(sys) # not equations()!
ieqs = ModelingToolkit.get_initialization_eqs(sys)
vars = ModelingToolkit.get_unknowns(sys)
pars = ModelingToolkit.get_ps(sys)
# TODO: forward more fields
return ODESystem(eqs, t, vars, pars; initialization_eqs=ieqs, name=sys.name)
end
# replace one subsystem by another
function replace(sys::ODESystem, old_new_subsys::Pair{ODESystem, ODESystem}; kwargs...)
old_subsys, new_subsys = old_new_subsys # unpack
fullname_target = ModelingToolkit.get_name(old_subsys) |> string
return transform((sys, fullname) -> (fullname == fullname_target ? new_subsys : identity(sys)), sys; kwargs...)
end
# factory for a stupid component
function stupidcomponent(xval; kwargs...)
@variables x(t)
return ODESystem([x ~ xval], t; kwargs...)
end
# create a hierarchical system
@named A = stupidcomponent(1)
@named B = stupidcomponent(1)
@named C = stupidcomponent(1)
@named S1 = compose(A, compose(A, B, C), C)
# now want to replace S1.A.C where x ~ 1 with a different C where x ~ 2
@named C = stupidcomponent(2)
@named S2 = replace(S1, S1.A.C => C)
Run this, and the component A.C
is changed:
julia> equations(S1)
5-element Vector{Equation}:
x(t) ~ 1
A₊x(t) ~ 1
A₊B₊x(t) ~ 1
A₊C₊x(t) ~ 1
C₊x(t) ~ 1
julia> equations(S2)
5-element Vector{Equation}:
x(t) ~ 1
A₊x(t) ~ 1
A₊B₊x(t) ~ 1
A₊C₊x(t) ~ 2
C₊x(t) ~ 1
Would love to see anyone improve on this! Can this or something similar be incorporated into the library?
If you want to replace all occurances of a subsystem, you can use substitute
with a Dict
of system names to new systems and that will replace all the occurrences of the un-namespaced system name with the new system.
For example, in the above, you would have
S2 = substitute(S1, Dict(:C => C))
and this will give
julia> equations(S2)
5-element Vector{Equation}:
x(t) ~ 1
A₊x(t) ~ 1
A₊B₊x(t) ~ 1
A₊C₊x(t) ~ 2
C₊x(t) ~ 2
Note that both A₊C₊x
and C₊x
were changed.
Beware, this is a super dangerous feature that I wish we didn't have :O
Yeah, I'm not sure if this is public API. It's not documented as far as I can tell 😅
Modelica has the replaceable keyword to enable models that have replaceable components. This is useful in model libraries, where the user might want to replace one or several of the components in a larger model.
In MTK, our current option is to require the author of the model library to ensure that there are input arguments to the constructor of every model to allow the user to select model components.
As an example, consider a model component that models a heat pump, this model is likely to have hundreds of sub-models. Deep inside this model, I as a user want to replace a friction model to something more detailed, how do I do this? If I own the model library, I could make all the required changes to all constructors to take the friction model as an argument, but if I do not own the model library?