Change parameters of array components in ModelingToolkit.jl

Hello all,

I am looking for a way of setting the individual parameters of an array of components in ModelingToolkit.

Consider the following example (inspired by the ModelingToolkit docs):

using ModelingToolkit
using ModelingToolkit: t

@mtkmodel ModelA begin
    @parameters begin
        k
        k_array[1:2]
    end
end

@mtkmodel ModelB begin
    @parameters begin
        p1 = 1.0, [description = "Parameter of ModelB"]
        p2 = 1.0, [description = "Parameter of ModelB"]
    end
end

@mtkmodel ModelC begin
    @icon "https://github.com/SciML/SciMLDocs/blob/main/docs/src/assets/logo.png"
    @constants begin
        c::Int = 1, [description = "Example constant."]
    end
    @structural_parameters begin
        f = sin
        N = 2
    end
    begin
        v_var = 1.0
    end
    @variables begin
        v(t) = v_var
        v_array(t)[1:2, 1:3]
        v_for_defaults(t)
    end
    @extend ModelB(; p1)
    @components begin
	model_array_a = [ModelA(; k = i) for i in 1:N]
        model_array_b = for i in 1:N
            k = i^2
            ModelA(; k)
        end
    end
    @equations begin
        sum([m.k for m in model_array_a]) ~ f(v)
    end
    @defaults begin
        v_for_defaults => 2.0
    end
end

@mtkbuild model_c = ModelC()

In this case, the k variables of model_array_b are set in the for loop.
But in my use case I want to run run my model hundreds of times with slightly different parameters each time.
To do this efficiently, I have to change the parameters each time, for example using the setp function.

But the only way I have found to access these parameters, is by doing something like @mtkbuild model_c2 = ModelC(; model_array_a.k = 11.0).
This works, but does not allow me to set the k’s of model_array_a to individually different values, using the parameter interface (i.e. not a for loop).

Does anyone know of a way of doing this?

If you use a parameter array then you have to set it with an array of the same size.

I can’t quite get it to work.

When I do something like @mtkbuild model_c = ModelC(; model_array_a.k = [i for i in 1:2]) I get an error saying TypeError: in keyword argument k, expected Union{Nothing, Real}, got a value of type Vector{Int64}.

Adding something along the lines of

@mtkmodel ModelC begin
    @icon "https://github.com/SciML/SciMLDocs/blob/main/docs/src/assets/logo.png"
    @constants begin
        c::Int = 1, [description = "Example constant."]
    end
	@parameters begin
		new_k_array[1:2]::Float64
	end
    @structural_parameters begin
        f = sin
        N = 2
    end
    begin
        v_var = 1.0
    end
    @variables begin
        v(t) = v_var
        v_array(t)[1:2, 1:3]
        v_for_defaults(t)
    end
    @extend ModelB(; p1)
    @components begin
		model_array_a = [ModelA(; k = new_k_array[i]) for i in 1:N]
        model_array_b = for i in 1:N
            k = i^2
            ModelA(; k)
        end
    end
    @equations begin
        sum([m.k for m in model_array_a]) ~ f(v)
    end
    @defaults begin
        v_for_defaults => 2.0
    end
end

@mtkbuild model_c1 = ModelC(; new_k_array = [Float64(i) for i in 1:2])

prob = ODEProblem(model_c1, [], (0., 100.0), [])

yields the error MethodError: Cannot convert an object of type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64.

Am I doing something wrong?

This is not a Float64

@ven-k do we have a good issue to point to?

Correct, I’m following the instructions from the ModelingToolkit docs, which says to use the eltype of the array, as described here.