Skip to content

Commit

Permalink
all changes; here g(t) = gval needs gval to be a param and g is acces…
Browse files Browse the repository at this point in the history
…sible as g
  • Loading branch information
ven-k committed Jun 26, 2023
1 parent a7f77f3 commit 21dc3da
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 47 deletions.
70 changes: 43 additions & 27 deletions src/systems/model_parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ for f in (:connector, :model)
macro $f(name::Symbol, body)
esc($(Symbol(f, :_macro))(__module__, name, body))
end

macro $f(fcall::Expr, body)
fcall.head == :call || "Couldn't comprehend the $f $arg"

arglist, kwargs = if lastindex(fcall.args) > 1 && is_kwarg(fcall.args[2])
(lastindex(fcall.args) > 2 ? Set(fcall.args[3:end]) : Set()),
Set(fcall.args[2].args)
else
Set(), Set(fcall.args[2:end])
end
esc($(Symbol(f, :_macro))(__module__, fcall.args[1], body; arglist, kwargs))
end
end
end

Expand All @@ -43,14 +31,15 @@ function connector_macro(mod, name, body; arglist = Set([]), kwargs = Set([]))
vs = []
icon = Ref{Union{String, URI}}()
dict = Dict{Symbol, Any}()
dict[:kwargs] = Dict{Symbol, Any}()
expr = Expr(:block)
for arg in body.args
arg isa LineNumberNode && continue
if arg.head == :macrocall && arg.args[1] == Symbol("@icon")
parse_icon!(icon, dict, dict, arg.args[end])
continue
end
parse_variable_arg!(expr, vs, dict, mod, arg, :variables)
parse_variable_arg!(expr, vs, dict, mod, arg, :variables, kwargs)
end
iv = get(dict, :independent_variable, nothing)
if iv === nothing
Expand All @@ -68,18 +57,33 @@ function connector_macro(mod, name, body; arglist = Set([]), kwargs = Set([]))
end
end

function parse_variable_def!(dict, mod, arg, varclass)
function parse_variable_def!(dict, mod, arg, varclass, kwargs, def = nothing)
arg isa LineNumberNode && return
MLStyle.@match arg begin
::Symbol => (generate_var!(dict, arg, varclass), nothing)
Expr(:call, a, b) => (generate_var!(dict, a, b, varclass), nothing)
a::Symbol => begin
push!(kwargs, Expr(:kw, a, def))
var = generate_var!(dict, a, varclass)
dict[:kwargs][getname(var)] = def
@info 75 dict[:kwargs]
(var, nothing)
end
Expr(:call, a, b) => begin
push!(kwargs, Expr(:kw, a, def))
var = generate_var!(dict, a, b, varclass)
dict[:kwargs][getname(var)] = def
(var, nothing)
end
Expr(:(=), a, b) => begin
var, _ = parse_variable_def!(dict, mod, a, varclass)
Base.remove_linenums!(b)
def, meta = parse_default(mod, b)
var, _ = parse_variable_def!(dict, mod, a, varclass, kwargs, def)
dict[varclass][getname(var)][:default] = def
if typeof(def) != Symbol
var = setdefault(var, def)
def = nothing
else
def in [keys(dict[:kwargs])...;] || error("$def is not a known parameter or variable")
var = setdefault(var, def)
end
if !isnothing(meta)
if (ct = get(meta, VariableConnectType, nothing)) !== nothing
Expand All @@ -90,7 +94,7 @@ function parse_variable_def!(dict, mod, arg, varclass)
(var, def)
end
Expr(:tuple, a, b) => begin
var, _ = parse_variable_def!(dict, mod, a, varclass)
var, _ = parse_variable_def!(dict, mod, a, varclass, kwargs)
meta = parse_metadata(mod, b)
if (ct = get(meta, VariableConnectType, nothing)) !== nothing
dict[varclass][getname(var)][:connection_type] = nameof(ct)
Expand All @@ -110,6 +114,7 @@ function generate_var(a, varclass)
end

function generate_var!(dict, a, varclass)
#var = generate_var(Symbol("#", a), varclass)
var = generate_var(a, varclass)
vd = get!(dict, varclass) do
Dict{Symbol, Dict{Symbol, Any}}()
Expand All @@ -128,6 +133,7 @@ function generate_var!(dict, a, b, varclass)
Dict{Symbol, Dict{Symbol, Any}}()
end
vd[a] = Dict{Symbol, Any}()
# var = Symbolics.variable(Symbol("#", a), T = SymbolicUtils.FnType{Tuple{Real}, Real})(iv)
var = Symbolics.variable(a, T = SymbolicUtils.FnType{Tuple{Real}, Real})(iv)
if varclass == :parameters
var = toparam(var)
Expand All @@ -145,6 +151,15 @@ function parse_default(mod, a)
(def, meta)
end
::Symbol || ::Number => (a, nothing)
Expr(:call, a...) => begin
# @info "expr call" a
def = parse_default.(Ref(mod), a)
expr = Expr(:call)
for (d, _) in def
push!(expr.args, d)
end
(expr, nothing)
end
_ => error("Cannot parse default $a")
end
end
Expand All @@ -169,8 +184,10 @@ function get_var(mod::Module, b)
end

function model_macro(mod, name, expr; arglist = Set([]), kwargs = Set([]))
# @info 214 "here"
exprs = Expr(:block)
dict = Dict{Symbol, Any}()
dict[:kwargs] = Dict{Symbol, Any}()
comps = Symbol[]
ext = Ref{Any}(nothing)
eqs = Expr[]
Expand Down Expand Up @@ -198,7 +215,7 @@ function model_macro(mod, name, expr; arglist = Set([]), kwargs = Set([]))
nothing

sys = :($ODESystem($Equation[$(eqs...)], $iv, [$(vs...)], [$(ps...)];
systems = [$(comps...)], name, gui_metadata = $gui_metadata))
systems = [$(comps...)], name, gui_metadata = $gui_metadata)) #, defaults = $defaults))
if ext[] === nothing
push!(exprs.args, sys)
else
Expand All @@ -217,9 +234,9 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
elseif mname == Symbol("@extend")
parse_extend!(exprs, ext, dict, body)
elseif mname == Symbol("@variables")
parse_variables!(exprs, vs, dict, mod, body, :variables)
parse_variables!(exprs, vs, dict, mod, body, :variables, kwargs)
elseif mname == Symbol("@parameters")
parse_variables!(exprs, ps, dict, mod, body, :parameters)
parse_variables!(exprs, ps, dict, mod, body, :parameters, kwargs)
elseif mname == Symbol("@equations")
parse_equations!(exprs, eqs, dict, body)
elseif mname == Symbol("@icon")
Expand Down Expand Up @@ -321,21 +338,20 @@ function parse_extend!(exprs, ext, dict, body)
end
end

function parse_variable_arg!(expr, vs, dict, mod, arg, varclass)
vv, def = parse_variable_def!(dict, mod, arg, varclass)
function parse_variable_arg!(expr, vs, dict, mod, arg, varclass, kwargs)
vv, _ = parse_variable_def!(dict, mod, arg, varclass, kwargs)
v = Num(vv)
name = getname(v)
push!(vs, name)
def === nothing ? push!(expr.args, :($name = $v)) :
push!(expr.args, :($name = $setdefault($v, $def)))
push!(expr.args, :($name = $name === nothing ? $vv : $setdefault($vv, $name)))
end

function parse_variables!(exprs, vs, dict, mod, body, varclass)
function parse_variables!(exprs, vs, dict, mod, body, varclass, kwargs)
expr = Expr(:block)
push!(exprs, expr)
for arg in body.args
arg isa LineNumberNode && continue
parse_variable_arg!(expr, vs, dict, mod, arg, varclass)
parse_variable_arg!(expr, vs, dict, mod, arg, varclass, kwargs)
end
end

Expand Down
46 changes: 26 additions & 20 deletions test/model_parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ end
@connector RealOutput begin
u(t), [output = true]
end
@model Constant(; k = 1) begin
@model Constant begin
@components begin
output = RealOutput()
end
@parameters begin
k = k, [description = "Constant output value of block"]
k, [description = "Constant output value of block"]
end
@equations begin
output.u ~ k
Expand All @@ -25,13 +25,13 @@ end
@variables t
D = Differential(t)

@connector Pin(; v_start = 0) begin
v(t) = v_start # Potential at the pin [V]
@connector Pin begin
v(t) # Potential at the pin [V]
i(t), [connect = Flow] # Current flowing into the pin [A]
@icon "pin.png"
end

@named p = Pin(; v_start = π)
@named p = Pin(; v = π)
@test getdefault(p.v) == π

@model OnePort begin
Expand Down Expand Up @@ -64,10 +64,10 @@ end
end

resistor_log = "$(@__DIR__)/logo/resistor.svg"
@model Resistor(; R = 1) begin
@model Resistor begin
@extend v, i = oneport = OnePort()
@parameters begin
R = R
R
end
@icon begin
"""<?xml version="1.0" encoding="UTF-8"?>
Expand All @@ -90,10 +90,10 @@ l15 0" stroke="black" stroke-width="1" stroke-linejoin="bevel" fill="none"></pat
end
end

@model Capacitor(; C = 1) begin
@model Capacitor begin
@extend v, i = oneport = OnePort()
@parameters begin
C = C
C
end
@icon "https://upload.wikimedia.org/wikipedia/commons/7/78/Capacitor_symbol.svg"
@equations begin
Expand All @@ -116,7 +116,7 @@ end
resistor = Resistor(; R)
capacitor = Capacitor(; C = 10)
source = Voltage()
constant = Constant()
constant = Constant(; k = 1)
ground = Ground()
end
@equations begin
Expand Down Expand Up @@ -145,33 +145,39 @@ end

@test length(equations(structural_simplify(rc))) == 1

@model MockModel(; cval, gval, jval = 6) begin
@model MockModel begin
@parameters begin
a
b(t)
c(t) = cval
cval
jval
kval
c(t) = cval + cval
d = 2
e, [description = "e"]
f = 3, [description = "f"]
g = gval, [description = "g"]
h(t), [description = "h(t)"]
i(t) = 5, [description = "i(t)"]
i(t) = 4, [description = "i(t)"]
j(t) = jval, [description = "j(t)"]
k = kval, [description = "k"]
end
end

@named model = MockModel(cval = 1, gval = 4)
kval = 5
@named model = MockModel(; kval, cval = 1)

@test hasmetadata(model.e, VariableDescription)
@test hasmetadata(model.f, VariableDescription)
@test hasmetadata(model.g, VariableDescription)
@test hasmetadata(model.h, VariableDescription)
@test hasmetadata(model.i, VariableDescription)
@test hasmetadata(model.j, VariableDescription)
@test hasmetadata(model.k, VariableDescription)

@test getdefault(model.c) == 1
@test getdefault(model.cval) == 1
@test getdefault(model.c) == 2
@test getdefault(model.d) == 2
@test_throws KeyError getdefault(model.e)
@test getdefault(model.f) == 3
@test getdefault(model.g) == 4
@test getdefault(model.i) == 5
@test getdefault(model.j) == 6
@test getdefault(model.i) == 4
@test getdefault(model.j) == :jval
@test getdefault(model.k) == kval

0 comments on commit 21dc3da

Please sign in to comment.