From dc1adfccef57044345b492b37543cd7744a3338c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20W=C3=BCrfel?= Date: Mon, 27 Oct 2025 17:50:10 +0100 Subject: [PATCH] add test for passing params as structural params it is common to define composite systems, where the parameters and their names are defined in the "outer" system. Passing them as structural parameters ensures, that there is only one parameter holding that information (which can be changed with a callback for example) rather than having multiple parameters which just share the same default values. --- test/model_parsing.jl | 86 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/test/model_parsing.jl b/test/model_parsing.jl index 2c713d4149..6a3e29fda4 100644 --- a/test/model_parsing.jl +++ b/test/model_parsing.jl @@ -1089,3 +1089,89 @@ end @test ModelingToolkit.getmetadata(test_model, MyBool, nothing) === false @test ModelingToolkit.getmetadata(test_model, NewInt, nothing) === 1 end + +@testset "Pass parameters of higher level models as structural parameters" begin + let D=ModelingToolkit.D_nounits, t=ModelingToolkit.t_nounits + """ + ╭─────────╮ + in │ K │ out + ╶─>─┤ ------- ├──>─╴ + │ 1 + s T │ + ╰─────────╯ + """ + @mtkmodel SimpleLag begin + @structural_parameters begin + K # Gain + T # Time constant + end + @variables begin + in(t), [description="Input signal", input=true] + out(t), [description="Output signal", output=true] + end + @equations begin + T * D(out) ~ K*in - out + end + end + + """ + ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ DoubleLag ┃ + ┃ ╭─────────╮ ╭─────────╮ ┃ + in ┃ │ K1 │ │ K2 │ ┃ out + ─>──╂─┤ ------- ├──┤ ------- ├─╂──>──╴ + ┃ │ 1 + sT1 │ │ 1 + sT2 │ ┃ + ┃ ╰─────────╯ ╰─────────╯ ┃ + ┗━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + """ + @mtkmodel DoubleLag begin + @parameters begin + K1, [description="Proportional gain 1"] + T1, [description="Time constant 1"] + K2, [description="Proportional gain 2"] + T2, [description="Time constant 2"] + end + @components begin + lag1 = SimpleLag(K = K1, T = T1) + lag2 = SimpleLag(K = K2, T = T2) + end + @variables begin + in(t), [description="Input signal", input=true] + out(t), [description="Output signal", output=true] + end + @equations begin + in ~ lag1.in + lag1.out ~ lag2.in + out ~ lag2.out + end + end + + @mtkmodel ClosedSystem begin + @components begin + double_lag = DoubleLag(; K1 = 1, K2 = 2, T1 = 0.1, T2 = 0.2) + end + @equations begin + double_lag.in ~ 1.0 + end + end + + @mtkbuild sys = ClosedSystem() + @test length(parameters(sys)) == 4 + @test length(unknowns(sys)) == 2 + + p = MTKParameters(sys, defaults(sys)) + u = [0.5 for i in 1:2] + du = zeros(2) + # update du for given u and p + ODEFunction(sys).f.f_iip(du, u, p, 0.0) + + # find indices of lag1 and lag2 states (might be reordered due to simplification details) + symnames = string.(ModelingToolkit.getname.(variable_symbols(sys))) + lag1idx = findall(contains("1"), symnames) |> only + lag2idx = findall(contains("2"), symnames) |> only + + # check du values + K1, K2, T1, T2 = 1, 2, 0.1, 0.2 + @test du[lag1idx] ≈ (K1*1.0 - u[lag1idx]) / T1 + @test du[lag2idx] ≈ (K2*u[lag1idx] - u[lag2idx]) / T2 + end +end