Skip to content

Commit 5f2cfd7

Browse files
committed
Parse simple models into Model
1 parent a1aac3a commit 5f2cfd7

File tree

1 file changed

+66
-21
lines changed

1 file changed

+66
-21
lines changed

src/systems/connectors.jl

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ macro connector(name::Symbol, body)
1414
esc(connector_macro((@__MODULE__), name, body))
1515
end
1616

17+
struct Model{F, S}
18+
f::F
19+
structure::S
20+
end
21+
(m::Model)(args...; kw...) = m.f(args...; kw...)
22+
1723
using MLStyle
1824
function connector_macro(mod, name, body)
1925
if !Meta.isexpr(body, :block)
@@ -32,33 +38,55 @@ function connector_macro(mod, name, body)
3238
dict = Dict{Symbol, Any}()
3339
for arg in body.args
3440
arg isa LineNumberNode && continue
35-
push!(vs, Num(parse_variable_def!(dict, mod, arg)))
41+
push!(vs, Num(parse_variable_def!(dict, mod, arg, :variables)))
3642
end
3743
iv = get(dict, :independent_variable, nothing)
38-
if iv === nothing
44+
if iv === nothing
3945
error("$name doesn't have a independent variable")
4046
end
41-
ODESystem(Equation[], iv, vs, []; name)
47+
quote
48+
$name = $Model((; name) -> $ODESystem($(Equation[]), $iv, $vs, $([]); name), $dict)
49+
end
4250
end
4351

44-
function parse_variable_def!(dict, mod, arg)
52+
function parse_variable_def!(dict, mod, arg, varclass)
4553
MLStyle.@match arg begin
46-
::Symbol => generate_var(arg)
47-
Expr(:call, a, b) => generate_var!(dict, a, set_iv!(dict, b))
48-
Expr(:(=), a, b) => setdefault(parse_variable_def!(dict, mod, a), parse_default(mod, b))
49-
Expr(:tuple, a, b) => set_var_metadata(parse_variable_def!(dict, mod, a), parse_metadata(mod, b))
54+
::Symbol => generate_var(arg, varclass)
55+
Expr(:call, a, b) => generate_var!(dict, a, set_iv!(dict, b), varclass)
56+
Expr(:(=), a, b) => begin
57+
var = parse_variable_def!(dict, mod, a, varclass)
58+
def = parse_default(mod, b)
59+
dict[varclass][getname(var)][:default] = def
60+
setdefault(var, def)
61+
end
62+
Expr(:tuple, a, b) => begin
63+
var = parse_variable_def!(dict, mod, a, varclass)
64+
meta = parse_metadata(mod, b)
65+
if (ct = get(meta, VariableConnectType, nothing)) !== nothing
66+
dict[varclass][getname(var)][:connection_type] = nameof(ct)
67+
end
68+
set_var_metadata(var, meta)
69+
end
5070
_ => error("$arg cannot be parsed")
5171
end
5272
end
5373

5474
generate_var(a) = Symbolics.variable(a)
55-
function generate_var!(dict, a, b)
75+
function generate_var!(dict, a, b, varclass)
5676
iv = generate_var(b)
5777
prev_iv = get!(dict, :independent_variable) do
5878
iv
5979
end
6080
@assert isequal(iv, prev_iv)
61-
Symbolics.variable(a, T = SymbolicUtils.FnType{Tuple{Real}, Real})(iv)
81+
vd = get!(dict, varclass) do
82+
Dict{Symbol, Dict{Symbol, Any}}()
83+
end
84+
vd[a] = Dict{Symbol, Any}()
85+
var = Symbolics.variable(a, T = SymbolicUtils.FnType{Tuple{Real}, Real})(iv)
86+
if varclass == :parameters
87+
var = toparam(var)
88+
end
89+
var
6290
end
6391
function set_iv!(dict, b)
6492
prev_b = get!(dict, :independent_variable_name) do
@@ -78,7 +106,7 @@ function parse_default(mod, a)
78106
end
79107
function parse_metadata(mod, a)
80108
MLStyle.@match a begin
81-
Expr(:vect, eles...) => map(Base.Fix1(parse_metadata, mod), eles)
109+
Expr(:vect, eles...) => Dict(parse_metadata(mod, e) for e in eles)
82110
Expr(:(=), a, b) => Symbolics.option_to_metadata_type(Val(a)) => get_var(mod, b)
83111
_ => error("Cannot parse metadata $a")
84112
end
@@ -97,54 +125,71 @@ macro model(name::Symbol, expr)
97125
end
98126
function model_macro(mod, name, expr)
99127
exprs = Expr(:block)
128+
dict = Dict{Symbol, Any}()
100129
for arg in expr.args
101130
arg isa LineNumberNode && continue
102131
arg.head == :macrocall || error("$arg is not valid syntax. Expected a macro call.")
103-
parse_model!(exprs.args, mod, arg)
132+
parse_model!(exprs.args, dict, mod, arg)
133+
end
134+
iv = get(dict, :independent_variable, nothing)
135+
if iv === nothing
136+
error("$name doesn't have a independent variable")
104137
end
105-
exprs
138+
push!(exprs.args,
139+
:($ODESystem(var"#___eqs___", $iv, var"#___vs___", $([]);
140+
systems = var"#___comps___", name)))
141+
:($name = $Model((; name) -> $exprs, $dict))
106142
end
107-
function parse_model!(exprs, mod, arg)
143+
function parse_model!(exprs, dict, mod, arg)
108144
mname = arg.args[1]
109145
vs = Num[]
110-
dict = Dict{Symbol, Any}()
111146
body = arg.args[end]
112147
if mname == Symbol("@components")
113148
parse_components!(exprs, dict, body)
114149
elseif mname == Symbol("@variables")
115-
parse_variables!(exprs, vs, dict, mod, body)
150+
parse_variables!(exprs, vs, dict, mod, body, :variables)
116151
elseif mname == Symbol("@equations")
117152
parse_equations!(exprs, dict, body)
118153
else
119154
error("$mname is not handled.")
120155
end
121156
end
122157
function parse_components!(exprs, dict, body)
158+
expr = Expr(:block)
159+
push!(exprs, expr)
123160
comps = Pair{String, String}[]
124-
comp_name = Symbol("#___comp___")
161+
names = Symbol[]
125162
for arg in body.args
126163
arg isa LineNumberNode && continue
127164
MLStyle.@match arg begin
128165
Expr(:(=), a, b) => begin
166+
push!(names, a)
129167
arg = deepcopy(arg)
130168
b = deepcopy(arg.args[2])
131169
push!(b.args, Expr(:kw, :name, Meta.quot(a)))
132170
arg.args[2] = b
133171
push!(comps, String(a) => readable_code(b))
134-
push!(exprs, @show arg)
172+
push!(expr.args, arg)
135173
end
136174
_ => error("`@components` only takes assignment expressions. Got $arg")
137175
end
138176
end
177+
push!(expr.args, :(var"#___comps___" = [$(names...)]))
139178
dict[:components] = comps
140179
end
141-
function parse_variables!(exprs, vs, dict, mod, body)
180+
function parse_variables!(exprs, vs, dict, mod, body, varclass)
181+
expr = Expr(:block)
182+
push!(exprs, expr)
183+
names = Symbol[]
142184
for arg in body.args
143185
arg isa LineNumberNode && continue
144-
v = Num(parse_variable_def!(dict, mod, arg))
186+
v = Num(parse_variable_def!(dict, mod, arg, varclass))
145187
push!(vs, v)
146-
push!(exprs, :($(getname(v)) = $v))
188+
name = getname(v)
189+
push!(names, name)
190+
push!(expr.args, :($name = $v))
147191
end
192+
push!(expr.args, :(var"#___vs___" = [$(names...)]))
148193
end
149194
function parse_equations!(exprs, dict, body)
150195
eqs = :(Equation[])

0 commit comments

Comments
 (0)