Skip to content

Commit 1359630

Browse files
feat: mark inputs and outputs of FMU with appropriate metadata
1 parent 9614c03 commit 1359630

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

ext/MTKFMIExt.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ function MTK.FMIComponent(::Val{Ver}; fmu = nothing, tolerance = 1e-6,
132132
# parse the inputs to the FMU
133133
inputs = []
134134
fmi_variables_to_mtk_variables!(fmu, FMI.getInputValueReferencesAndNames(fmu),
135-
value_references, inputs, states, observed)
135+
value_references, inputs, states, observed; postprocess_variable = v -> MTK.setinput(
136+
v, true))
136137
# create a symbolic variable for the input buffer
137138
if isempty(inputs)
138139
__mtk_internal_x = []
@@ -145,7 +146,8 @@ function MTK.FMIComponent(::Val{Ver}; fmu = nothing, tolerance = 1e-6,
145146
# parse the outputs of the FMU
146147
outputs = []
147148
fmi_variables_to_mtk_variables!(fmu, FMI.getOutputValueReferencesAndNames(fmu),
148-
value_references, outputs, states, observed)
149+
value_references, outputs, states, observed; postprocess_variable = v -> MTK.setoutput(
150+
v, true))
149151
# create the output buffer. This is only required for CoSimulation to pass it to
150152
# the callback affect
151153
if type == :CS
@@ -284,18 +286,22 @@ defaults.
284286
# Keyword Arguments
285287
- `parameters`: A boolean indicating whether to use `@parameters` for the symbolic
286288
variables instead of `@variables`.
289+
- `postprocess_variable`: A function applied to each created variable that should
290+
return the updated variable. This is useful to add metadata to variables.
287291
"""
288292
function fmi_variables_to_mtk_variables!(
289293
fmu::Union{FMI.FMU2, FMI.FMU3}, varmap::AbstractDict,
290294
value_references::AbstractDict, truevars, allvars,
291-
obseqs, defs = Dict(); parameters = false)
295+
obseqs, defs = Dict(); parameters = false, postprocess_variable = identity)
292296
for (valRef, snames) in varmap
293297
stateT = FMI.dataTypeForValueReference(fmu, valRef)
294298
snames = map(parseFMIVariableName, snames)
295299
if parameters
296-
vars = [MTK.unwrap(only(@parameters $sname::stateT)) for sname in snames]
300+
vars = [postprocess_variable(MTK.unwrap(only(@parameters $sname::stateT)))
301+
for sname in snames]
297302
else
298-
vars = [MTK.unwrap(only(@variables $sname(t)::stateT)) for sname in snames]
303+
vars = [postprocess_variable(MTK.unwrap(only(@variables $sname(t)::stateT)))
304+
for sname in snames]
299305
end
300306
for i in eachindex(vars)
301307
if i == 1

test/extensions/fmi.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ const FMU_DIR = joinpath(@__DIR__, "fmus")
99
truesol = FMI.simulate(
1010
fmu, (0.0, 8.0); saveat = 0.0:0.1:8.0, recordValues = ["mass.s", "mass.v"])
1111

12+
function test_no_inputs_outputs(sys)
13+
for var in unknowns(sys)
14+
@test !MTK.isinput(var)
15+
@test !MTK.isoutput(var)
16+
end
17+
end
1218
@testset "v2, ME" begin
1319
fmu = loadFMU("SpringPendulum1D", "Dymola", "2022x"; type = :ME)
1420
@mtkbuild sys = MTK.FMIComponent(Val(2); fmu, type = :ME)
21+
test_no_inputs_outputs(sys)
1522
prob = ODEProblem{true, SciMLBase.FullSpecialize}(
1623
sys, [sys.mass__s => 0.5, sys.mass__v => 0.0], (0.0, 8.0))
1724
sol = solve(prob, Tsit5(); reltol = 1e-8, abstol = 1e-8)
@@ -28,6 +35,7 @@ const FMU_DIR = joinpath(@__DIR__, "fmus")
2835
Val(2); fmu, communication_step_size = 0.001, type = :CS)
2936
@variables x(t) = 1.0
3037
@mtkbuild sys = ODESystem([D(x) ~ x], t; systems = [inner])
38+
test_no_inputs_outputs(sys)
3139

3240
prob = ODEProblem{true, SciMLBase.FullSpecialize}(
3341
sys, [sys.inner.mass__s => 0.5, sys.inner.mass__v => 0.0], (0.0, 8.0))
@@ -44,6 +52,7 @@ const FMU_DIR = joinpath(@__DIR__, "fmus")
4452
@testset "v3, ME" begin
4553
fmu = loadFMU("SpringPendulum1D", "Dymola", "2023x", "3.0"; type = :ME)
4654
@mtkbuild sys = MTK.FMIComponent(Val(3); fmu, type = :ME)
55+
test_no_inputs_outputs(sys)
4756
prob = ODEProblem{true, SciMLBase.FullSpecialize}(
4857
sys, [sys.mass__s => 0.5, sys.mass__v => 0.0], (0.0, 8.0))
4958
sol = solve(prob, Tsit5(); reltol = 1e-8, abstol = 1e-8)
@@ -60,6 +69,7 @@ const FMU_DIR = joinpath(@__DIR__, "fmus")
6069
Val(3); fmu, communication_step_size = 0.001, type = :CS)
6170
@variables x(t) = 1.0
6271
@mtkbuild sys = ODESystem([D(x) ~ x], t; systems = [inner])
72+
test_no_inputs_outputs(sys)
6373

6474
prob = ODEProblem{true, SciMLBase.FullSpecialize}(
6575
sys, [sys.inner.mass__s => 0.5, sys.inner.mass__v => 0.0], (0.0, 8.0))
@@ -75,6 +85,11 @@ end
7585
@testset "v2, ME" begin
7686
fmu = loadFMU(joinpath(FMU_DIR, "SimpleAdder.fmu"); type = :ME)
7787
@named adder = MTK.FMIComponent(Val(2); fmu, type = :ME)
88+
@test MTK.isinput(adder.a)
89+
@test MTK.isinput(adder.b)
90+
@test MTK.isoutput(adder.out)
91+
@test !MTK.isinput(adder.c) && !MTK.isoutput(adder.c)
92+
7893
@variables a(t) b(t) c(t) [guess = 1.0]
7994
@mtkbuild sys = ODESystem(
8095
[adder.a ~ a, adder.b ~ b, D(a) ~ t,
@@ -92,6 +107,10 @@ end
92107
fmu = loadFMU(joinpath(FMU_DIR, "SimpleAdder.fmu"); type = :CS)
93108
@named adder = MTK.FMIComponent(
94109
Val(2); fmu, type = :CS, communication_step_size = 0.001)
110+
@test MTK.isinput(adder.a)
111+
@test MTK.isinput(adder.b)
112+
@test MTK.isoutput(adder.out)
113+
@test !MTK.isinput(adder.c) && !MTK.isoutput(adder.c)
95114
@variables a(t) b(t) c(t) [guess = 1.0]
96115
@mtkbuild sys = ODESystem(
97116
[adder.a ~ a, adder.b ~ b, D(a) ~ t,
@@ -110,6 +129,9 @@ end
110129
@testset "v3, ME" begin
111130
fmu = loadFMU(joinpath(FMU_DIR, "StateSpace.fmu"); type = :ME)
112131
@named sspace = MTK.FMIComponent(Val(3); fmu, type = :ME)
132+
@test MTK.isinput(sspace.u)
133+
@test MTK.isoutput(sspace.y)
134+
@test !MTK.isinput(sspace.x) && !MTK.isoutput(sspace.x)
113135
@variables u(t)=1.0 x(t)=1.0 y(t) [guess = 1.0]
114136
@mtkbuild sys = ODESystem(
115137
[sspace.u ~ u, D(u) ~ t, D(x) ~ sspace.x + sspace.y, y^2 ~ sspace.y + x], t;
@@ -125,6 +147,9 @@ end
125147
fmu = loadFMU(joinpath(FMU_DIR, "StateSpace.fmu"); type = :CS)
126148
@named sspace = MTK.FMIComponent(
127149
Val(3); fmu, communication_step_size = 1e-3, type = :CS)
150+
@test MTK.isinput(sspace.u)
151+
@test MTK.isoutput(sspace.y)
152+
@test !MTK.isinput(sspace.x) && !MTK.isoutput(sspace.x)
128153
@variables u(t)=1.0 x(t)=1.0 y(t) [guess = 1.0]
129154
@mtkbuild sys = ODESystem(
130155
[sspace.u ~ u, D(u) ~ t, D(x) ~ sspace.x + sspace.y, y^2 ~ sspace.y + x], t;

0 commit comments

Comments
 (0)