ModelingToolkit change parameter vector size based on structural parameter

Hi all, I’m trying to model a nonlinear component with @mtkmodel in ModelingToolkit.

The base model with a given nonlinerity order (3 in this case) is

@mtkmodel NLComponent begin
    @parameters begin
        r[1:3]
    end

    @components begin
        origin = Flange()
        target = Flange()
    end

    @variables begin
        l(t)
        c(t)
    end

    @equations begin
        l ~ origin.s - target.s
        c ~ -(sum(r[p] * l^p for p in axes(r, 1)))
    end
end

While that works fine, I’m trying to allow the component to support generic polynomial non-linearity. I tried to make this work with a structural_parameter to specify the order of the non-linearity, though it would have been even better to have the size be inferred from the size of r directly, but that does not seem feasible.

@mtkmodel NLComponent begin
    @structural_parameters begin
        n = 1
    end
    @parameters begin
        r[1:n]
    end

    @components begin
        origin = Flange()
        target = Flange()
    end

    @variables begin
        l(t)
        c(t)
    end

    @equations begin
        l ~ origin.s - target.s
        c ~ -(sum(r[p] * l^p for p in axes(r, 1)))
    end
end

However that does not work as well and fails with

ERROR: LoadError: promotion of types Int64 and Symbol failed to change any arguments
Stacktrace:
[1] error(::String, ::String, ::String)
@ Base .\error.jl:44
[2] sametype_error(input::Tuple{Int64, Symbol})
@ Base .\promotion.jl:417
[3] not_sametype(x::Tuple{Int64, Symbol}, y::Tuple{Int64, Symbol})
@ Base .\promotion.jl:411
[4] promote
@ .\promotion.jl:394 [inlined]
[5] UnitRange(start::Int64, stop::Symbol)
@ Base .\range.jl:408
[6] (::ModelingToolkit.var"#174#175")(i::Expr)
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:181
[7] iterate(g::Base.Generator, s::Vararg{Any})
@ Base .\generator.jl:47 [inlined]
[8] _collect(c::SubArray{…}, itr::Base.Generator{…}, ::Base.EltypeUnknown, isz::Base.HasShape{…})
@ Base .\array.jl:854
[9] collect_similar
@ .\array.jl:763 [inlined]
[10] map
@ .\abstractarray.jl:3282 [inlined]
[11] parse_variable_def!(dict::Dict{…}, mod::Module, arg::Expr, varclass::Symbol, kwargs::Set{…}; def::Nothing, indices::Nothing)
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:181
[12] parse_variable_def!
@ D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:109 [inlined]
[13] parse_variable_arg(dict::Dict{Symbol, Any}, mod::Module, arg::Expr, varclass::Symbol, kwargs::Set{Any})
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:428
[14] parse_variable_arg!(exprs::Vector{…}, vs::Vector{…}, dict::Dict{…}, mod::Module, arg::Expr, varclass::Symbol, kwargs::Set{…})
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:422
[15] parse_variables!(exprs::Vector{…}, vs::Vector{…}, dict::Dict{…}, mod::Module, body::Expr, varclass::Symbol, kwargs::Set{…})
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:533
[16] parse_model!(exprs::Vector{…}, comps::Vector{…}, ext::Base.RefValue{…}, eqs::Vector{…}, icon::Base.RefValue{…}, vs::Vector{…}, ps::Vector{…}, sps::Vector{…}, dict::Dict{…}, mod::Module, arg::Expr, kwargs::Set{…})
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:292
[17] _model_macro(mod::Module, name::Symbol, expr::Expr, isconnector::Bool)
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:55
[18] var"@mtkmodel"(source::LineNumberNode, module::Module, name::Symbol, body::Any)
@ ModelingToolkit D:<user>.julia\packages\ModelingToolkit\Gpzyo\src\systems\model_parsing.jl:31

I thought that structural_parameters where designed for such branching of the code, but I’m probably using them the wrong way.
Side note, @structural_parameters does not seem to be exported in ModelingToolkit v8.75.0

Yeah, I have noticed this error. RN, parameter and variable array length should be defined while defining the model.

I plan to change of couple of things to allow users to pass array length.

Thanks, do you want me to open an issue ? Can you confirm there is no problem with writing the summation this way in the @equations block ?

I’ve created this: Allow variable array length for parameters in `@mtkmodel` · Issue #2453 · SciML/ModelingToolkit.jl · GitHub

The equations came out

julia> equations(nlc)
2-element Vector{Equation}:
 l(t) ~ -target₊s(t) + origin₊s(t)
 c(t) ~ -r[1]*l(t) - r[2]*(l(t)^2) - r[3]*(l(t)^3)

Looks good to me.