fix: drop equations from scc_eqs whose matched variable is outside the SCC#82
Closed
baggepinnen wants to merge 1 commit into
Closed
fix: drop equations from scc_eqs whose matched variable is outside the SCC#82baggepinnen wants to merge 1 commit into
scc_eqs whose matched variable is outside the SCC#82baggepinnen wants to merge 1 commit into
Conversation
…the SCC
`get_sorted_scc` builds `scc_eqs` by iterating `for v in scc` and pushing
`full_var_eq_matching[v]` if it is an `Int`. Stale entries in
`full_var_eq_matching` left behind by the dummy-derivative pass can map a
variable inside the current SCC to an equation that is *also* matched (via
`var_eq_matching`) to a different variable outside this SCC. When such an
equation enters `scc_eqs`, `generate_system_equations!` pushes the outside
variable's index into `var_ordering` from this SCC's codegen, while another
SCC simultaneously pushes the same index from its own codegen, causing the
duplicate-state assertion at `reassemble.jl:499` to fire:
"Tearing internal error: lowering DAE into semi-implicit ODE failed!"
Filtering `scc_eqs` to keep only equations whose `eq_var_matching` target
is either `Unassigned` or inside the SCC removes the spurious cross-SCC
overlap without affecting well-formed systems.
Verified on the rolling-wheel reproducer in `JuliaComputing/MultibodyComponents.jl`,
branch `rolling_wheel` (`MultibodyComponents.tests.WheelInWorld`), which previously
threw the error during `multibody(model)` and now reaches `solve`.
Sibling `SlipWheelInWorld` (which already compiled) continues to compile
and integrate to `t_end = 3.0` with `retcode = Success`. The MTKTearing
test suite has the same 2 pre-existing `trivial_tearing!` failures both
with and without this change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Member
|
This is an interesting bug. While the diagnosis is correct, I don't think the solution is. |
Member
|
This is very incorrect and as such I'm closing the PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the "Tearing internal error: lowering DAE into semi-implicit ODE failed!" thrown at
reassemble.jl:499for systems where the dummy-derivative pass leaves stale entries infull_var_eq_matchingthat causeget_sorted_sccto pull equations into an SCC'sscc_eqswhoseeq_var_matchingvalue points at a variable outside that SCC. When this happens, two distinct SCCs end up emitting differential equations for the same state-variable index (viapush!(var_ordering, diff_to_var[iv])), tripping the duplicate-state-var assertion.The fix filters
scc_eqsinget_sorted_sccto keep only equations whose matched variable is eitherUnassignedor inside the SCC. This drops the spurious cross-SCC overlap without affecting well-formed systems.Root cause
In
generate_system_equations!,var_orderingis filled from two push sites:reassemble.jl:460(linear-SCC inline path):push!(var_ordering, ∫iv)with∫iv = diff_to_var[iv]reassemble.jl:837(generalcodegen_equation!derivative-variable branch):push!(var_ordering, diff_to_var[iv])For a duplicate to occur in
var_ordering[is_diff_eq], two distinct matchedivs must satisfydiff_to_var[iv₁] == diff_to_var[iv₂]. In the failing case this happens because the sameiv = D(angles[2])is processed twice — once in a singleton SCC matched to the joint'sder_angles[2] ~ D(angles[2])equation, and once again in a separate (large, linsol-able) SCC whosevsccwas populated byget_sorted_sccpulling in that joint equation throughfull_var_eq_matching[v]for somevin the larger SCC'sscclist.Concretely, with the rolling-wheel reproducer below,
get_sorted_sccproduces:scc = [1, 47, 8, 29, 45, 69, 71, 72, 73, 74, 75, 76, 138, …](24 entries, no2)scc_eqs(final)of size 25 includingeq 14eq_var_matching[14] = 2, soscc_varsends up with2injected at position 17 even though2 ∉ sccThe big SCC and the singleton SCC for var
2then both pushdiff_to_var[2] = 20intovar_ordering.Reproducer
Repo:
JuliaComputing/MultibodyComponents.jl, branchrolling_wheel, HEADf531433.Stack of the failing pre-PR error:
After this PR,
multibody(model)completes; the siblingSlipWheelInWorldtest (which already compiled) continues to compile and integrate tot_end = 3.0withretcode = Success.Regression test
Not included here. The bug only surfaces with the dummy-derivative alias pattern produced by the multibody port; minimal 2D rolling-disk MTK-only models (with and without acceleration-level kinetics) compile cleanly both with and without this fix, so they don't witness the bug. The rolling-wheel reproducer above is the smallest known trigger; happy to backport a regression test if a smaller MTK-only MWE is found.
Test plan
mtkcompile(MultibodyComponents.tests.WheelInWorld())succeeds (previously threwTearing internal error).MultibodyComponents.tests.SlipWheelInWorldstill compiles + integrates tot_end = 3.0,retcode = Success.Pkg.test("ModelingToolkitTearing")shows the same 2 pre-existingtrivial_tearing!failures with and without this change — no regression.🤖 Generated with Claude Code