You can always put @macroexpand
before a macro call in the REPL to see exactly what it’s doing. Here is the result of that on for the Pin
case from the MTK docs (I deleted line number comments to make it more readable):
julia> @macroexpand @connector function Pin(;name)
sts = @variables v(t)=1.0 i(t)=1.0
ODESystem(Equation[], t, sts, []; name=name)
end
quote
struct Pin
var"##275"->begin
1
end
end
function Pin(; name)
function f()
begin
sts = begin
v = (identity)((Symbolics.wrap)((Symbolics.setdefaultval)(((Sym){(SymbolicUtils.FnType){NTuple{1, Any}, Real}}(:v))((Symbolics.value)(t)), begin
1.0
end)))
i = (identity)((Symbolics.wrap)((Symbolics.setdefaultval)(((Sym){(SymbolicUtils.FnType){NTuple{1, Any}, Real}}(:i))((Symbolics.value)(t)), begin
1.0
end)))
[v, i]
end
ODESystem(Equation[], t, sts, []; name = name)
end
end
res = f()
if (isdefined)(res, :connection_type)
var"#131#lens" = (identity)((Setfield.compose)((Setfield.PropertyLens){:connection_type}()))
res = (Setfield.set)(res, var"#131#lens", Pin)
else
res
end
end
end
So it’s creating a struct called Pin
, doing some fancy trickery to delete it’s default constructor (I think?), then creating a Pin
method that calls your code and then sets the connection_type
of the output to the type Pin
.
This can be especially useful if your model has different types of connections. Let’s say it has electrical Pin
s as defined above, but also rotational mechanical Flange
s that are basically the same, but with angular velocity instead of current and torque instead of voltage. This might look like:
@connector function Flange(;name)
sts = @variables τ(t)=1.0 ω(t)=1.0
ODESystem(Equation[], t, sts, []; name=name)
end
Now you can write pretty generic code that takes advantage of circuit analogies for other domains. For example, you can have generic functions to get the flow and effort variables from a connector as:
flow_variable(connector) = flow_variable(ModelingToolkit.get_connection_type(connector), connector)
flow_variable(::Type{Pin}, connector) = connector.i
flow_variable(::Type{Flange}, connector) = connector.ω
effort_variable(connector) = effort_variable(ModelingToolkit.get_connection_type(connector), connector)
effort_variable(::Type{Pin}, connector) = connector.v
effort_variable(::Type{Flange}, connector) = connector.τ