Skip to content

Commit c52d4c8

Browse files
authored
Merge pull request #208 from JuliaDynamics/hw/implicitoutputs
handle fully implicit outputs in mtk models
2 parents bb36c6a + 2ba1552 commit c52d4c8

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

ext/MTKExt.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,27 +274,41 @@ function generate_io_function(_sys, inputss::Tuple, outputss::Tuple;
274274
alloutputs = reduce(union, outputss)
275275

276276
missing_inputs = Set{Symbolic}()
277+
implicit_outputs = Set{Symbolic}() # fully implicit outputs which do not appear in the equations
277278
sys = if ModelingToolkit.iscomplete(_sys)
278279
deepcopy(_sys)
279280
else
280281
_openinputs = setdiff(allinputs, Set(parameters(_sys)))
281282
all_eq_vars = mapreduce(get_variables, union, full_equations(_sys), init=Set{Symbolic}())
282283
if !(_openinputs all_eq_vars)
283284
missing_inputs = setdiff(_openinputs, all_eq_vars)
284-
@warn "The specified inputs ($missing_inputs) do not appear in the equations of the system!"
285+
verbose && @warn "The specified inputs ($missing_inputs) do not appear in the equations of the system!"
285286
_openinputs = setdiff(_openinputs, missing_inputs)
286287
end
287-
structural_simplify(_sys, (_openinputs, alloutputs); simplify=false)[1]
288+
_definedoutputs = alloutputs all_eq_vars
289+
if !(Set(_definedoutputs) == Set(alloutputs))
290+
implicit_outputs = setdiff(alloutputs, _definedoutputs)
291+
verbose && @warn "The specified outputs $implicit_outputs do not appear in the equations of the system!"
292+
end
293+
structural_simplify(_sys, (_openinputs, _definedoutputs); simplify=false)[1]
288294
end
289295

290-
states = unknowns(sys)
291296
allparams = parameters(sys) # contains inputs!
292297
@argcheck allinputs Set(allparams) missing_inputs
293298
params = setdiff(allparams, Set(allinputs))
294299

295300
# extract the main equations and observed equations
296301
eqs::Vector{Equation} = full_equations(sys)
297302
fix_metadata!(eqs, sys);
303+
304+
# assert the ordering of states and equations
305+
explicit_states = Symbolic[eq_type(eq)[2] for eq in eqs if !isnothing(eq_type(eq)[2])]
306+
implicit_states = setdiff(unknowns(sys), explicit_states) implicit_outputs
307+
states = map(eqs) do eq
308+
type = eq_type(eq)
309+
isnothing(type[2]) ? pop!(implicit_states) : type[2]
310+
end
311+
298312
# check hat there are no rhs differentials in the equations
299313
if !isempty(rhs_differentials(eqs))
300314
diffs = rhs_differentials(eqs)
@@ -389,7 +403,7 @@ function generate_io_function(_sys, inputss::Tuple, outputss::Tuple;
389403
# filter out unnecessary parameters
390404
var_deps = _all_rhs_symbols(eqs)
391405
unused_params = Set(setdiff(params, (var_deps out_deps))) # do not exclud obs_deps
392-
if verbose && !isempth(unused_params)
406+
if verbose && !isempty(unused_params)
393407
@info "Parameters $(unused_params) do not appear in equations of f and g and will be marked as unused."
394408
end
395409

test/MTK_test.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,27 @@ v = VertexModel(nestedswing, [:i_r, :i_i], [:u_r, :u_i])
233233
data = NetworkDynamics.rand_inputs_fg(v)
234234
b = @b $(NetworkDynamics.compfg(v))($data...)
235235
@test b.allocs == 0
236+
237+
238+
# test fully implicit outputs
239+
@mtkmodel FullyImplicit begin
240+
@variables begin
241+
u(t), [description = "Input Variable", input=true]
242+
x(t), [description = "Explicit Variable"]
243+
y(t), [description = "Implicit Variable, present in equations"]
244+
z(t), [description = "fully implicit variable, not present but output", output=true]
245+
end
246+
@equations begin
247+
Dt(x) ~ -x
248+
0 ~ sqrt(y+x)
249+
0 ~ u # implicitly forces z becaus u(z)
250+
end
251+
end
252+
@named fullyimplicit = FullyImplicit()
253+
v = VertexModel(fullyimplicit, [:u], [:z])
254+
@test v.mass_matrix == LinearAlgebra.Diagonal([1,0,0])
255+
@test v.sym == [:x, :z, :y]
256+
257+
data = NetworkDynamics.rand_inputs_fg(v)
258+
b = @b $(NetworkDynamics.compfg(v))($data...)
259+
@test b.allocs == 0

0 commit comments

Comments
 (0)