In MTK, how can I change a system's parameter's default values?

I have a sys::System, and I’d like to build a sys2 that is like sys, but sys2.some_param’s default is 20. Right now I use

"""
``jldoctest
julia> @named sys = MySystem();

julia> param = sys.some_param;

julia> initial_conditions(assign_parameters(sys, [param=>14]))[vol]
14
``
"""
assign_parameters(sys::System, new_params::AbstractDict) =
    MTK.@set sys.initial_conditions = merge(initial_conditions(sys), new_params)

to achieve that, but this is ugly code that uses MTK internals. It also does not work if the Dict contains some_param[2] => new_value; I have to pass some_param => new_array.

I’m aware that “Don’t do this; pass the new parameters as the ps parameter” might be the official answer, but it’s not very satisfying. Given that sys has parameters, it feels natural that we could change them. remake does not seem defined for it.

For context, I want to have sys2 = fit_parameters(sys, my_data). I could of course have it return the new parameters, but I’d prefer to return the new system.

Probably better as an issue to discuss adding such a function.

I have a package I’m working on that can solve this problem: bradcarman/ModelingToolkitParameters.jl: Parameter Management utility for ModelingToolkit models. You can see the initial docs here: docs that explain the full concept.

For your example, the solutions would look like this…

# standard defaults
@named sys = MySystem()

# special defaults
motor_params = MotorParams(r=20)
@named sys2 = MySystem(; motor_params)

The full MWE…

using ModelingToolkit
using ModelingToolkit: D_nounits as D, t_nounits as t
using ModelingToolkitParameters

@kwdef mutable struct MotorParams <: Params
    k::Float64 = 0.1
    r::Float64 = 0.01
    l::Float64 = 1e-3
end

@component function Motor(; name)
  pars = @parameters begin
    k 
    r
    l
  end
  vars = @variables begin
    v(t)
    dphi(t) = 0
    i(t) = 0
    di(t)
  end
  eqs = Equation[
    D(i) ~ di
    v ~ i * r + l * di + dphi * k
    D(dphi) ~ k * i
    v ~ sin(t)
  ]

  return ODESystem(eqs, t, vars, pars; name)
end

@component function MySystem(; name, motor_params = MotorParams())
    systems = @named begin
        motor = Motor()
    end
    defaults = motor => motor_params
    return System(Equation[], t, [], []; name, defaults, systems)
end

# standard defaults
@named sys = MySystem()

# special defaults
motor_params = MotorParams(r=20)
@named sys2 = MySystem(; motor_params)
1 Like