From 08742b61ae4a44f123f5569c02f3bbf7b8978fe9 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Fri, 16 Feb 2024 14:55:45 +0100 Subject: [PATCH 1/4] wip: add StructIO --- src/Blocks/utils.jl | 38 ++++++++++++++++++++++++++++++++++++++ test/Blocks/sources.jl | 29 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/Blocks/utils.jl b/src/Blocks/utils.jl index d6200d85b..2f0cf59bf 100644 --- a/src/Blocks/utils.jl +++ b/src/Blocks/utils.jl @@ -107,3 +107,41 @@ Base class for a multiple input multiple output (MIMO) continuous system block. ] return ODESystem(eqs, t, vcat(u..., y...), []; name = name, systems = [input, output]) end + + + +@connector function StructInput(; structdef, name) + n = Symbolics.juliatype(structdef) + @variables u(t)::n [input = true] # Dummy default value due to bug in Symbolics + ODESystem(Equation[], t, [u], []; name) +end + +@connector function StructOutput(; structdef, name) + n = Symbolics.juliatype(structdef) + @variables u(t)::n [output = true] # Dummy default value due to bug in Symbolics + ODESystem(Equation[], t, [u], []; name) +end + +function _structelem2connector(elem::StructElement) + T = Symbolics.decodetyp(elem.typ) + if T <: Bool + return BoolOutput(; name = elem.name) + elseif T <: Real + return RealOutput(; name = elem.name) + end +end + +@component function BusSelect(;name, structdef, selected_fields) + @parameters t + nout = length(selected_fields) + inputbus = Blocks.StructInput(; structdef, name = Symbol("inputbus")) + @variables input(t) + + output_elements = filter(e->e.name in selected_fields, getelements(structdef)) + output_connectors = map(_structelem2connector, output_elements) + + eqs = [ + getproperty(inputbus.u, field) ~ con.u for (field, con) in zip(selected_fields, output_connectors) + ] + return ODESystem(eqs, t; name = name, systems = [inputbus; output_connectors]) +end \ No newline at end of file diff --git a/test/Blocks/sources.jl b/test/Blocks/sources.jl index b1df8f21b..5080e9b11 100644 --- a/test/Blocks/sources.jl +++ b/test/Blocks/sources.jl @@ -474,3 +474,32 @@ end @test sol[ddy][end]≈2 atol=1e-3 end end + +using Symbolics +using Symbolics: Struct, StructElement, getelements, symstruct +using Test +using ModelingToolkitStandardLibrary.Blocks +using ModelingToolkitStandardLibrary.Blocks: structelem2connector + +# Test struct +struct BarStruct + speed::Float64 + isSpeedValid::Int +end + +bar = BarStruct(1.0, 1) +structdef = symstruct(BarStruct) +selected_fields = [:speed] + +@mtkmodel BusSelectTest begin + @components begin + inputbus = Blocks.StructOutput(; structdef) + output = BusSelect(; structdef, selected_fields) + end + @equations begin + inputbus.u ~ bar + connect(inputbus, output) + end +end + +@named sys = BusSelectTest() From 6e38240df6e627088b743c4d4a972d66d74e150c Mon Sep 17 00:00:00 2001 From: Yingbo Ma Date: Wed, 21 Feb 2024 09:11:22 -0500 Subject: [PATCH 2/4] Use https://github.com/JuliaSymbolics/Symbolics.jl/pull/1062 --- src/Blocks/Blocks.jl | 1 + src/Blocks/utils.jl | 11 +++++------ test/Blocks/sources.jl | 11 +++++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Blocks/Blocks.jl b/src/Blocks/Blocks.jl index cf0679a37..9bf4f8580 100644 --- a/src/Blocks/Blocks.jl +++ b/src/Blocks/Blocks.jl @@ -11,6 +11,7 @@ using ModelingToolkit: getdefault D = Differential(t) export RealInput, RealOutput, SISO +using Symbolics: Struct, StructElement, getelements, symstruct include("utils.jl") export Gain, Sum, MatrixGain, Feedback, Add, Add3, Product, Division diff --git a/src/Blocks/utils.jl b/src/Blocks/utils.jl index 2f0cf59bf..5b224dd06 100644 --- a/src/Blocks/utils.jl +++ b/src/Blocks/utils.jl @@ -110,15 +110,14 @@ end +using Symbolics: Struct, symbolic_getproperty @connector function StructInput(; structdef, name) - n = Symbolics.juliatype(structdef) - @variables u(t)::n [input = true] # Dummy default value due to bug in Symbolics + @variables u(t)::Struct [input = true] # Dummy default value due to bug in Symbolics ODESystem(Equation[], t, [u], []; name) end @connector function StructOutput(; structdef, name) - n = Symbolics.juliatype(structdef) - @variables u(t)::n [output = true] # Dummy default value due to bug in Symbolics + @variables u(t)::Struct [output = true] # Dummy default value due to bug in Symbolics ODESystem(Equation[], t, [u], []; name) end @@ -141,7 +140,7 @@ end output_connectors = map(_structelem2connector, output_elements) eqs = [ - getproperty(inputbus.u, field) ~ con.u for (field, con) in zip(selected_fields, output_connectors) + symbolic_getproperty(inputbus.u, field) ~ con.u for (field, con) in zip(selected_fields, output_connectors) ] return ODESystem(eqs, t; name = name, systems = [inputbus; output_connectors]) -end \ No newline at end of file +end diff --git a/test/Blocks/sources.jl b/test/Blocks/sources.jl index 5080e9b11..700a4db79 100644 --- a/test/Blocks/sources.jl +++ b/test/Blocks/sources.jl @@ -1,4 +1,4 @@ -using ModelingToolkit, ModelingToolkitStandardLibrary, OrdinaryDiffEq +using ModelingToolkit, ModelingToolkitStandardLibrary, OrdinaryDiffEq, Test using ModelingToolkitStandardLibrary.Blocks using ModelingToolkitStandardLibrary.Blocks: smooth_sin, smooth_cos, smooth_damped_sin, smooth_square, smooth_step, smooth_ramp, @@ -479,7 +479,8 @@ using Symbolics using Symbolics: Struct, StructElement, getelements, symstruct using Test using ModelingToolkitStandardLibrary.Blocks -using ModelingToolkitStandardLibrary.Blocks: structelem2connector +using ModelingToolkitStandardLibrary.Blocks: BusSelect +#using ModelingToolkitStandardLibrary.Blocks: structelem2connector # Test struct struct BarStruct @@ -491,14 +492,16 @@ bar = BarStruct(1.0, 1) structdef = symstruct(BarStruct) selected_fields = [:speed] +using Symbolics: Struct +@parameters bar_param::Struct @mtkmodel BusSelectTest begin @components begin inputbus = Blocks.StructOutput(; structdef) output = BusSelect(; structdef, selected_fields) end @equations begin - inputbus.u ~ bar - connect(inputbus, output) + inputbus.u ~ bar_param + connect(inputbus, output.inputbus) end end From cb3c397dd20b9901f369738b7f9971bb9ef6265a Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Thu, 22 Feb 2024 06:37:09 +0100 Subject: [PATCH 3/4] wip --- test/Blocks/sources.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/Blocks/sources.jl b/test/Blocks/sources.jl index 700a4db79..b855fa398 100644 --- a/test/Blocks/sources.jl +++ b/test/Blocks/sources.jl @@ -488,13 +488,12 @@ struct BarStruct isSpeedValid::Int end -bar = BarStruct(1.0, 1) +bar = BarStruct(2.0, 1) structdef = symstruct(BarStruct) selected_fields = [:speed] -using Symbolics: Struct -@parameters bar_param::Struct @mtkmodel BusSelectTest begin + @parameters bar_param::Struct @components begin inputbus = Blocks.StructOutput(; structdef) output = BusSelect(; structdef, selected_fields) @@ -506,3 +505,11 @@ using Symbolics: Struct end @named sys = BusSelectTest() +sys = complete(sys) +ssys = structural_simplify(sys) +prob = ODEProblem(ssys, [ + sys.bar_param => bar + ], (0.0, 1.0)) +sol = solve(prob, Rodas4()) +@test sol.retcode == ReturnCode.Success +@test sol[sys.output.speed.u] == 2.0 \ No newline at end of file From 5401a99c0841105c9defb27d03a18a20a25ba3cc Mon Sep 17 00:00:00 2001 From: Yingbo Ma Date: Mon, 26 Feb 2024 13:55:17 -0500 Subject: [PATCH 4/4] Fix tests and mark mtkmodel macro broken --- test/Blocks/sources.jl | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/test/Blocks/sources.jl b/test/Blocks/sources.jl index b855fa398..27e09e680 100644 --- a/test/Blocks/sources.jl +++ b/test/Blocks/sources.jl @@ -492,6 +492,20 @@ bar = BarStruct(2.0, 1) structdef = symstruct(BarStruct) selected_fields = [:speed] +@parameters bar_param::Struct +systems = @named begin + inputbus = Blocks.StructOutput(; structdef) + output = BusSelect(; structdef, selected_fields) +end +eqs = [inputbus.u ~ bar_param + connect(inputbus, output.inputbus)] +@named sys = ODESystem(eqs, t; systems) +sys = complete(sys) +ssys = structural_simplify(sys) +prob = ODEProblem(ssys, [], (0.0, 1.0), [sys.bar_param => bar], tofloat=false) +sol = solve(prob, Rodas4()) +@test sol(1.0, idxs = sys.output.speed.u) == 2.0 + @mtkmodel BusSelectTest begin @parameters bar_param::Struct @components begin @@ -507,9 +521,11 @@ end @named sys = BusSelectTest() sys = complete(sys) ssys = structural_simplify(sys) -prob = ODEProblem(ssys, [ - sys.bar_param => bar - ], (0.0, 1.0)) -sol = solve(prob, Rodas4()) -@test sol.retcode == ReturnCode.Success -@test sol[sys.output.speed.u] == 2.0 \ No newline at end of file +@test_broken begin + prob = ODEProblem(ssys, [ + sys.bar_param => bar + ], (0.0, 1.0)) + sol = solve(prob, Rodas4()) + @test sol.retcode == ReturnCode.Success + @test sol(1.0, idxs = sys.output.speed.u) == 2.0 +end