Skip to content

Commit 7be1162

Browse files
committed
fix: improve handling of expression in metadata
The variables in mtkmodel can have complicated expressions as `guess` and other metadata. Instead of evaluating them while defining the mtk-model, make those exprs part of the the definition. Along with this, the metadata (in structure dict) is kept in expr form.
1 parent 335c7ba commit 7be1162

File tree

3 files changed

+54
-23
lines changed

3 files changed

+54
-23
lines changed

docs/src/basics/MTKModel_Connector.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,12 +408,13 @@ The conditional parts are reflected in the `structure`. For `BranchOutsideTheBlo
408408

409409
```julia
410410
julia> BranchOutsideTheBlock.structure
411-
Dict{Symbol, Any} with 6 entries:
411+
Dict{Symbol, Any} with 7 entries:
412412
:components => Any[(:if, :flag, Vector{Union{Expr, Symbol}}[[:sys1, :C]], Any[])]
413413
:kwargs => Dict{Symbol, Dict}(:flag=>Dict{Symbol, Bool}(:value=>1))
414414
:structural_parameters => Dict{Symbol, Dict}(:flag=>Dict{Symbol, Bool}(:value=>1))
415415
:independent_variable => t
416-
:parameters => Dict{Symbol, Dict{Symbol, Any}}(:a2 => Dict(:type => AbstractArray{Real}, :condition => (:if, :flag, Dict{Symbol, Any}(:kwargs => Dict{Any, Any}(:a1 => Dict{Symbol, Union{Nothing, DataType}}(:value => nothing, :type => Real)), :parameters => Any[Dict{Symbol, Dict{Symbol, Any}}(:a1 => Dict(:type => AbstractArray{Real}))]), Dict{Symbol, Any}(:variables => Any[Dict{Symbol, Dict{Symbol, Any}}()], :kwargs => Dict{Any, Any}(:a2 => Dict{Symbol, Union{Nothing, DataType}}(:value => nothing, :type => Real)), :parameters => Any[Dict{Symbol, Dict{Symbol, Any}}(:a2 => Dict(:type => AbstractArray{Real}))]))), :a1 => Dict(:type => AbstractArray{Real}, :condition => (:if, :flag, Dict{Symbol, Any}(:kwargs => Dict{Any, Any}(:a1 => Dict{Symbol, Union{Nothing, DataType}}(:value => nothing, :type => Real)), :parameters => Any[Dict{Symbol, Dict{Symbol, Any}}(:a1 => Dict(:type => AbstractArray{Real}))]), Dict{Symbol, Any}(:variables => Any[Dict{Symbol, Dict{Symbol, Any}}()], :kwargs => Dict{Any, Any}(:a2 => Dict{Symbol, Union{Nothing, DataType}}(:value => nothing, :type => Real)), :parameters => Any[Dict{Symbol, Dict{Symbol, Any}}(:a2 => Dict(:type => AbstractArray{Real}))]))))
416+
:parameters => Dict{Symbol, Dict{Symbol, Any}}(:a2 => Dict(:type=>AbstractArray{Real}, :condition=>(:if, :flag, Dict{Symbol, Any}(:kwargs=>Dict{Any, Any}(:a1=>Dict{Symbol, Union{Nothing, DataType}}(:value=>nothing, :type=>Real)), :parameters=>Any[Dict{Symbol, Dict{Symbol, Any}}(:a1=>Dict(:type=>AbstractArray{Real}))]), Dict{Symbol, Any}(:variables=>Any[Dict{Symbol, Dict{Symbol, Any}}()], :kwargs=>Dict{Any, Any}(:a2=>Dict{Symbol, Union{Nothing, DataType}}(:value=>nothing, :type=>Real)), :parameters=>Any[Dict{Symbol, Dict{Symbol, Any}}(:a2=>Dict(:type=>AbstractArray{Real}))]))), :a1 => Dict(:type=>AbstractArray{Real}, :condition=>(:if, :flag, Dict{Symbol, Any}(:kwargs=>Dict{Any, Any}(:a1=>Dict{Symbol, Union{Nothing, DataType}}(:value=>nothing, :type=>Real)), :parameters=>Any[Dict{Symbol, Dict{Symbol, Any}}(:a1=>Dict(:type=>AbstractArray{Real}))]), Dict{Symbol, Any}(:variables=>Any[Dict{Symbol, Dict{Symbol, Any}}()], :kwargs=>Dict{Any, Any}(:a2=>Dict{Symbol, Union{Nothing, DataType}}(:value=>nothing, :type=>Real)), :parameters=>Any[Dict{Symbol, Dict{Symbol, Any}}(:a2=>Dict(:type=>AbstractArray{Real}))]))))
417+
:defaults => Dict{Symbol, Any}(:a1=>10)
417418
:equations => Any[(:if, :flag, ["a1 ~ 0"], ["a2 ~ 0"])]
418419
```
419420

src/systems/model_parsing.jl

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
187187
var = generate_var!(dict, a, varclass; indices, type)
188188
update_kwargs_and_metadata!(dict, kwargs, a, def, indices, type, var,
189189
varclass, where_types)
190-
(var, def)
190+
return var, def, Dict()
191191
end
192192
Expr(:(::), a, type) => begin
193193
type = getfield(mod, type)
@@ -202,12 +202,12 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
202202
var = generate_var!(dict, a, b, varclass, mod; indices, type)
203203
update_kwargs_and_metadata!(dict, kwargs, a, def, indices, type, var,
204204
varclass, where_types)
205-
(var, def)
205+
return var, def, Dict()
206206
end
207207
Expr(:(=), a, b) => begin
208208
Base.remove_linenums!(b)
209209
def, meta = parse_default(mod, b)
210-
var, def = parse_variable_def!(
210+
var, def, _ = parse_variable_def!(
211211
dict, mod, a, varclass, kwargs, where_types; def, type)
212212
if dict[varclass] isa Vector
213213
dict[varclass][1][getname(var)][:default] = def
@@ -225,12 +225,13 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
225225
end
226226
end
227227
end
228-
var = set_var_metadata(var, meta)
228+
var, metadata_with_exprs = set_var_metadata(var, meta)
229+
return var, def, metadata_with_exprs
229230
end
230-
(var, def)
231+
return var, def, Dict()
231232
end
232233
Expr(:tuple, a, b) => begin
233-
var, def = parse_variable_def!(
234+
var, def, _ = parse_variable_def!(
234235
dict, mod, a, varclass, kwargs, where_types; type)
235236
meta = parse_metadata(mod, b)
236237
if meta !== nothing
@@ -244,9 +245,10 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
244245
end
245246
end
246247
end
247-
var = set_var_metadata(var, meta)
248+
var, metadata_with_exprs = set_var_metadata(var, meta)
249+
return var, def, metadata_with_exprs
248250
end
249-
(var, def)
251+
return var, def, Dict()
250252
end
251253
Expr(:ref, a, b...) => begin
252254
indices = map(i -> UnitRange(i.args[2], i.args[end]), b)
@@ -350,21 +352,33 @@ function parse_metadata(mod, a)
350352
end
351353
end
352354

355+
function _set_var_metadata!(metadata_with_exprs, a, m, v::Expr)
356+
push!(metadata_with_exprs, m => v)
357+
a
358+
end
359+
function _set_var_metadata!(metadata_with_exprs, a, m, v)
360+
wrap(set_scalar_metadata(unwrap(a), m, v))
361+
end
362+
353363
function set_var_metadata(a, ms)
364+
metadata_with_exprs = Dict{DataType, Expr}()
354365
for (m, v) in ms
355-
a = wrap(set_scalar_metadata(unwrap(a), m, v))
366+
if m == VariableGuess && v isa Symbol
367+
v = quote
368+
$v
369+
end
370+
end
371+
a = _set_var_metadata!(metadata_with_exprs, a, m, v)
356372
end
357-
a
373+
a, metadata_with_exprs
358374
end
359375

360376
function get_var(mod::Module, b)
361377
if b isa Symbol
362-
getproperty(mod, b)
363-
elseif b isa Expr
364-
Core.eval(mod, b)
365-
else
366-
b
378+
isdefined(mod, b) && return getproperty(mod, b)
379+
isdefined(@__MODULE__, b) && return getproperty(@__MODULE__, b)
367380
end
381+
b
368382
end
369383

370384
function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps, c_evts, d_evts,
@@ -595,10 +609,26 @@ function parse_variable_arg!(exprs, vs, dict, mod, arg, varclass, kwargs, where_
595609
end
596610

597611
function parse_variable_arg(dict, mod, arg, varclass, kwargs, where_types)
598-
vv, def = parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types)
612+
vv, def, metadata_with_exprs = parse_variable_def!(
613+
dict, mod, arg, varclass, kwargs, where_types)
599614
name = getname(vv)
600-
return vv isa Num ? name : :($name...),
601-
:($name = $name === nothing ? $setdefault($vv, $def) : $setdefault($vv, $name))
615+
616+
varexpr = quote
617+
$name = if $name === nothing
618+
$setdefault($vv, $def)
619+
else
620+
$setdefault($vv, $name)
621+
end
622+
end
623+
624+
metadata_expr = Expr(:block)
625+
for (k, v) in metadata_with_exprs
626+
push!(metadata_expr.args,
627+
:($name = $wrap($set_scalar_metadata($unwrap($name), $k, $v))))
628+
end
629+
630+
push!(varexpr.args, metadata_expr)
631+
return vv isa Num ? name : :($name...), varexpr
602632
end
603633

604634
function handle_conditional_vars!(

test/model_parsing.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,8 @@ end
376376

377377
@testset "Metadata in variables" begin
378378
metadata = Dict(:description => "Variable to test metadata in the Model.structure",
379-
:input => true, :bounds => (-1, 1), :connection_type => :Flow,
380-
:tunable => false, :disturbance => true, :dist => Normal(1, 1))
379+
:input => true, :bounds => :((-1, 1)), :connection_type => :Flow,
380+
:tunable => false, :disturbance => true, :dist => :(Normal(1, 1)))
381381

382382
@connector MockMeta begin
383383
m(t),
@@ -473,7 +473,7 @@ using ModelingToolkit: getdefault, scalarize
473473

474474
@named model_with_component_array = ModelWithComponentArray()
475475

476-
@test ModelWithComponentArray.structure[:parameters][:r][:unit] == u""
476+
@test eval(ModelWithComponentArray.structure[:parameters][:r][:unit]) == eval(u"")
477477
@test lastindex(parameters(model_with_component_array)) == 3
478478

479479
# Test the constant `k`. Manually k's value should be kept in sync here

0 commit comments

Comments
 (0)