Skip to content

Commit e34f3de

Browse files
committed
Give a warning for underconstrained variables forced to 0
@oxinabox noticed that the following MSL test https://github.com/SciML/ModelingToolkitStandardLibrary.jl/blob/0f0fae138fe202140a4862eccaaac734051dc44f/test/Mechanical/translational.jl has a test that depends on an underconstrained variable (either `free.f` or `acc.f` may be set to an arbitrary value without affecting the dynamics of the system). Our structural singularity removal logic detects these situations and chooses one variable arbitrarily to set to 0. However, it does so silently, so users are unaware that they likely have a modeling bug. This PR adds a warning when this happens. For example, the above mentioned test now gives: ``` ┌ Warning: The model is under-constrained. Variable acc₊flange₊f(t) was arbitrarily chosen to be set to 0. This may indicate a model bug! └ @ ModelingToolkit ~/.julia/dev/ModelingToolkit/src/systems/alias_elimination.jl:54 ``` This is styled as an overridable callback, so higher level modeling frameworks that use MTK as a library can hook into this to give more domain-specific errors if desired.
1 parent 3d428f7 commit e34f3de

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

src/systems/alias_elimination.jl

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using SymbolicUtils: Rewriters
22
using Graphs.Experimental.Traversals
33

4-
function alias_eliminate_graph!(state::TransformationState; kwargs...)
4+
function alias_eliminate_graph!(state::TransformationState;
5+
variable_underconstrained! = force_var_to_zero!, kwargs...)
56
mm = linear_subsys_adjmat!(state; kwargs...)
67
if size(mm, 1) == 0
78
return mm # No linear subsystems
89
end
910

1011
@unpack graph, var_to_diff, solvable_graph = state.structure
11-
mm = alias_eliminate_graph!(state, mm)
12+
mm = alias_eliminate_graph!(state, mm; variable_underconstrained!)
1213
s = state.structure
1314
for g in (s.graph, s.solvable_graph)
1415
g === nothing && continue
@@ -47,9 +48,17 @@ function alias_elimination!(state::TearingState; kwargs...)
4748
sys = state.sys
4849
complete!(state.structure)
4950
graph_orig = copy(state.structure.graph)
50-
mm = alias_eliminate_graph!(state; kwargs...)
51-
5251
fullvars = state.fullvars
52+
53+
function variable_underconstrained_mtk!(structure::SystemStructure,
54+
ils::SparseMatrixCLIL,
55+
v::Int)
56+
@warn "The model is under-constrained. Variable $(fullvars[v]) was arbitrarily chosen to be set to 0. This may indicate a model bug!"
57+
return force_var_to_zero!(structure, ils, v)
58+
end
59+
mm = alias_eliminate_graph!(state;
60+
variable_underconstrained! = variable_underconstrained_mtk!, kwargs...)
61+
5362
@unpack var_to_diff, graph, solvable_graph = state.structure
5463

5564
subs = Dict()
@@ -348,7 +357,22 @@ function do_bareiss!(M, Mold, is_linear_variables, is_highest_diff)
348357
(rank1, rank2, rank3, pivots)
349358
end
350359

351-
function alias_eliminate_graph!(state::TransformationState, ils::SparseMatrixCLIL)
360+
function force_var_to_zero!(structure::SystemStructure, ils::SparseMatrixCLIL, v::Int)
361+
@unpack graph, solvable_graph, eq_to_diff = structure
362+
@set! ils.nparentrows += 1
363+
push!(ils.nzrows, ils.nparentrows)
364+
push!(ils.row_cols, [v])
365+
push!(ils.row_vals, [convert(eltype(ils), 1)])
366+
add_vertex!(graph, SRC)
367+
add_vertex!(solvable_graph, SRC)
368+
add_edge!(graph, ils.nparentrows, v)
369+
add_edge!(solvable_graph, ils.nparentrows, v)
370+
add_vertex!(eq_to_diff)
371+
return ils
372+
end
373+
374+
function alias_eliminate_graph!(state::TransformationState, ils::SparseMatrixCLIL;
375+
variable_underconstrained! = force_var_to_zero!)
352376
@unpack structure = state
353377
@unpack graph, solvable_graph, var_to_diff, eq_to_diff = state.structure
354378
# Step 1: Perform Bareiss factorization on the adjacency matrix of the linear
@@ -360,15 +384,7 @@ function alias_eliminate_graph!(state::TransformationState, ils::SparseMatrixCLI
360384
rk1vars = BitSet(@view pivots[1:rank1])
361385
for v in solvable_variables
362386
v in rk1vars && continue
363-
@set! ils.nparentrows += 1
364-
push!(ils.nzrows, ils.nparentrows)
365-
push!(ils.row_cols, [v])
366-
push!(ils.row_vals, [convert(eltype(ils), 1)])
367-
add_vertex!(graph, SRC)
368-
add_vertex!(solvable_graph, SRC)
369-
add_edge!(graph, ils.nparentrows, v)
370-
add_edge!(solvable_graph, ils.nparentrows, v)
371-
add_vertex!(eq_to_diff)
387+
ils = variable_underconstrained!(structure, ils, v)
372388
end
373389

374390
return ils

0 commit comments

Comments
 (0)