Skip to content

collect_scoped_vars! silently skips array-typed equations (symtype <: Number check) #4392

@xtalax

Description

@xtalax

Summary

collect_scoped_vars! in ModelingToolkitBase/src/utils.jl:607 uses symtype(eq.lhs) <: Number to filter equations. This silently skips any equation whose LHS has an array symtype (e.g. ArrayMaker, ArrayOp). Variables in these equations are never collected/registered, causing downstream compilation failures.

MWE

using ModelingToolkit
using SymbolicUtils
using SymbolicUtils: SymReal, ArrayOp

@variables t
@variables x(t)[1:5]

# Create a simple ArrayOp expression (simplified from what MethodOfLines produces)
ix = SymbolicUtils.Sym{SymReal}(:i_x)
x_unwrap = Symbolics.unwrap(x)

# Build an array equation: Dt(x) ~ some_array_expression
# When this is passed to System(), collect_scoped_vars! will skip it
# because symtype(array_expr) <: AbstractArray, not <: Number

# The issue manifests when any system with ArrayMaker/ArrayOp equations
# goes through mtkcompile → complete() → discover_globalscoped() →
# collect_scoped_vars!

Realistic reproduction (requires MethodOfLines.jl):

using ModelingToolkit, MethodOfLines, DomainSets

@parameters t x
@variables u(..) v(..)

Dx = Differential(x)
Dt = Differential(t)

# Two-variable coupled system with interface boundaries
# produces ArrayMaker equations that hit this code path
eq = [Dt(u(t,x)) ~ Dx(v(t,x) * Dx(u(t,x))),
      Dt(v(t,x)) ~ Dx(u(t,x) * Dx(v(t,x)))]
bcs = [u(0,x) ~ sin(x), u(t,0) ~ 0.0, u(t,1) ~ 0.0,
       v(0,x) ~ cos(x), v(t,0) ~ 1.0, v(t,1) ~ 1.0]
domains = [t  Interval(0.0, 1.0), x  Interval(0.0, 1.0)]
@named sys = PDESystem(eq, bcs, domains, [t,x], [u(t,x), v(t,x)])

disc = MOLFiniteDifference([x => 0.1], t)
prob = discretize(sys, disc)
# Fails during mtkcompile when collect_scoped_vars! skips array equations

Root cause

In ModelingToolkitBase/src/utils.jl:602-624:

function collect_scoped_vars!(unknowns, parameters, sys, iv, ::Type{op} = Differential; depth = 1) where {op}
    if has_eqs(sys)
        for eq in equations(sys)
            eqtype_supports_collect_vars(eq) || continue
            if eq isa Equation
                symtype(eq.lhs) <: Number || continue   # ← THIS LINE
            end
            collect_vars!(unknowns, parameters, eq, iv, op; depth)
        end
    end
    ...
end

Line 607 checks symtype(eq.lhs) <: Number. For array-valued equations (where symtype returns AbstractArray{<:Real} or similar), this check fails and the equation is silently skipped via continue. The variables referenced in these equations are never registered with the system.

Suggested fix

ModelingToolkitBase already has is_numeric_symtype at utils.jl:968-969:

function is_numeric_symtype(T::Type)
    return T <: Number || T <: AbstractArray && is_numeric_symtype(eltype(T))
end

This correctly handles array types with numeric element types. Replace line 607:

- symtype(eq.lhs) <: Number || continue
+ is_numeric_symtype(symtype(eq.lhs)) || continue

This would allow array-valued equations through while still filtering non-numeric types.

Impact

This blocks ~3 tests in MethodOfLines.jl where mtkcompile is called on systems containing ArrayMaker equations (the array-based discretization path). The equations are valid — they represent bulk array operations over discretized PDE grids — but their array symtype causes them to be silently dropped during system completion.

Environment

  • ModelingToolkit v10.x (latest)
  • ModelingToolkitBase v3.x
  • SymbolicUtils v4.18.1
  • MethodOfLines.jl stencils branch

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions