Simple Algebra in MTK

Another beginner question… To what extent can I solve equations in MTK?

using ModelingToolKit

@mtkmodel Scratch begin
    @variables begin
		x(t)
		y(t)
    end
    @equations begin
		x ~ 3y + 10
		y ~ 2x - 5
    end
end

@mtkbuild fols = Scratch()

probs = ODEProblem(fols, [], (0.0, 10.0), []);

yields MethodError: no method matching AbstractFloat(::Type{SymbolicUtils.BasicSymbolic{Real}}). Symbolics provides solve_for: Expression Manipulation · Symbolics.jl (juliasymbolics.org). Should I give up on @mtkmodel and write my equations using Symbolics.jl if I want to be able to call solve_for?

structural_simplify gives me The system is unbalanced. There are 2 highest order derivative variables and 1 equations., as it seemingly moved one of the equations into the observed.

How do people deal with these restrictions? Just accept that some of the algebra will be done by hand? I’d appreciate general wisdom, as MTK is rather intimidating at the moment…

Related: Using Modeling Toolkit to solve simple equation - Specific Domains / Modelling & Simulations - Julia Programming Language (julialang.org)

JuliaSimCompiler fully simplifies the system:

julia> structural_simplify(IRSystem(fols))
States (0):

Variables (2):
 1 => y
 2 => x
Matched SystemStructure with 2 equations and 2 variables
 #  ∂ₜ       eq           #  ∂ₜ       v
 1           [(1), 2]  |  1           [(1), 2]
 2           [1, 2]    |  2           [1, 2]

Legend: Solvable | (Solvable + Matched) | Unsolvable | (Unsolvable + Matched) |  ∫ SelectedState
1 Like

You have to call simplification for something to happen here, but ModelingToolkit by default will not solve linear equations. However, JuliaSimCompiler will do this

using ModelingToolKit

@mtkmodel Scratch begin
    @variables begin
		x(t)
		y(t)
    end
    @equations begin
		x ~ 3y + 10
		y ~ 2x - 5
    end
end

@named fols = Scratch()
fols = complete(fols)
ssys = structural_simplify(IRSystem(fols))

probs = ODEProblem(ssys, [], (0.0, 10.0), []);
sol = solve(probs, Tsit5())
julia> sol = solve(probs, Tsit5())
retcode: Success

julia> sol[[fols.x, fols.y]]
9-element Vector{Vector{Float64}}:
 [0.9999999999999999, -3.0]
1 Like

Your equations are not differential equations, but rather (linear) algebraic equations. So it looks strange to try to pose them as an ODEProblem.

An alternative approach:

using ModelingToolkit, NonlinearSolve

vars = @variables x y

# Define an algebraic system
eqs = [x ~ 3y + 10
        y ~ 2x - 5]
@mtkbuild sys = NonlinearSystem(eqs, vars, [])

OK – this doesn’t solve the equation symbolically, but you can proceed similarly as to for differential equations and create a NonlinearProblem and solve it. [There is also a LinearSolve.jl]

If I’m reading correctly, I could drop @mtkmodel, write the equations with Symbolics, and call solve_for manually. Apparently it’s limited to linear equations. Is JuliaSimCompiler able to solve more complicated systems?

MTK solves no systems at all, while JSCompiler currently solves linear systems. For JSCompiler to solve nonlinear systems inline is on the horizon.

When I say solve here, I mean that JSCompiler recognizes patterns like Ax = b in the dynamics and emits code for x = A\b, avoding the introduction of algebraic equations. MTK would treat this as a DAE system instead.

1 Like