ModelingToolkit.jl Documentation

repository·master·Indexed 23 days ago

https://github.com/sciml/modelingtoolkit.jl

A high-performance modeling framework for symbolic-numeric computation in Julia. It enables the definition of complex scientific models that are automatically optimized, sparsified, and transformed for efficient numerical simulation. Key features include hierarchical system composition using @component and @named, connection semantics via @connector, and a suite of code generation utilities for creating optimized RHS, Jacobians, and Hessians. It also supports dynamic optimization solvers with backends including JuMP, CasADi, InfiniteOpt, and Pyomo.

Tokens
54.3K
Snippets
112
Records
223
Agent score
82%

What's inside ModelingToolkit.jl

  1. Overview of ModelingToolkit.jl

    master

    ModelingToolkit.jl is a high-performance symbolic-numeric modeling language designed for scientific computing and scientific machine learning. It combines symbolic computational algebra (using Symbolics.jl) with causal (Simulink-style) and acausal (Modelica-style) equation-based modeling.

    Key capabilities include:

    • Symbolic Preprocessing: Automatic model transformation, simplification, and index reduction of differential-algebraic equations (DAEs).
    • Composition: Building complex models by connecting components using a lazy connection system.
    • Hybrid Modeling: Transforming systems of DAEs into optimization problems or vice-versa.
    • Parallelism: Pervasive parallelism in both symbolic computations and generated code.
    • Extensibility: Written in pure Julia, allowing users to add new simplification rules and transformations easily.
  2. Choose a backend for Dynamic Optimization Solvers

    master

    ModelingToolkit.jl supports four backends for solving dynamic optimization problems using collocation. The choice of backend determines how you pass the optimizer and how collocation methods are specified:

    1. JuMP and CasADi: Require an ODE tableau (constructed via DiffEqDevTools.constructX()). They expect the optimizer to be passed differently:
      • JuMP: Pass the optimizer object directly (e.g., Ipopt.Optimizer).
      • CasADi: Pass the solver name as a String (e.g., "ipopt").
    2. InfiniteOpt and Pyomo: Have built-in collocation methods and do not require an external ODE tableau.
      • InfiniteOpt: Pass the optimizer object directly. Defaults to FiniteDifference(Backward()) (implicit Euler) if no method is provided.
      • Pyomo: Pass the solver name as a String. Defaults to LagrangeRadau(3) if no method is provided.
  3. What is `modelingtoolkitize`?

    master

    modelingtoolkitize is a function in ModelingToolkit that automatically translates a numerically-defined SciMLProblem (such as those used in DifferentialEquations.jl, NonlinearSolve.jl, or Optimization.jl) into its symbolic ModelingToolkit equivalent (a System).

    This allows you to leverage symbolic analysis and transformations—such as deriving analytical Jacobians, determining equation sparsity, performing index reduction, or tearing—on existing numerical code before passing it to a solver.

    Limitations and Requirements

    • Compatibility: The code must be able to trace equations using Symbolics.jl Num types. Generally, if your code is compatible with forward-mode automatic differentiation, it is compatible with modelingtoolkitize.
    • Control Flow: modelingtoolkitize cannot preserve control flow structures like loops. Loops will be unrolled into large symbolic expressions, which may increase compilation times and potentially reduce LLVM SIMD vectorization.
  4. Handle underdetermined and overdetermined systems during initialization

    master

    When initializing an ODEProblem, the system must be well-formed (the number of equations must match the number of unknowns).

    • Underdetermined systems: Occur when you provide fewer conditions than required. ModelingToolkit will issue a warning. The system can still be solved, but the solution may not be unique.
    • Overdetermined systems: Occur when you provide more conditions than can be satisfied. If the conditions are analytically impossible to satisfy, the solver will return SciMLBase.ReturnCode.InitialFailure.

    To change the behavior for non-fully determined systems:

    • Use fully_determined = true in the ODEProblem constructor to receive an error instead of a warning.
    • Use warn_initialize_determined = false to suppress warnings about non-fully determined systems.
  5. Build and solve numerical problems in ModelingToolkit.jl

    master
    ModelingToolkit.jl automates the process of converting a symbolic System into a numerical problem type that solvers can understand. Numerical solvers require functions with specific argument and return value signatures. ModelingToolkit compiles and generates the necessary code to bridge the gap between symbolic equations and these required numerical formats.
  6. Compare methods for re-creating problems

    master

    There are several ways to re-create a problem with new state or parameter values in ModelingToolkit.jl/SciML, each with different performance and type-flexibility trade-offs:

    MethodUse CasePerformanceNotes
    Pure remakeGeneric updates, symbolic maps, or partial updates.LowMost flexible but slowest; can be hard for the compiler to infer.
    remake + setp/setuUpdating values when types do not change.Highremake(prob) creates an inferred copy; setp (parameters) or setu (unknowns) modifies values.
    replace + remakeChanging the type of parameters (e.g., for Automatic Differentiation).Highreplace creates a new parameter object with new types; remake applies it to the problem.
    replace! + remakeBulk replacement when types do not change.HighOperates in-place; useful for optimization methods not using dual numbers.
  7. How default values work for discrete variables

    master

    When defining variables in a discrete system, you can provide default values. These are treated as the value of the variable at all past timesteps.

    For example, in a Fibonacci sequence model:

    @variables x(t) = 1.0
    @mtkcompile sys = System([x ~ x(k - 1) + x(k - 2)], t)

    In this case, the default value 1.0 is applied to all past timesteps. Therefore, x(k-1) and x(k-2) both evaluate to 1.0, making the initial value of x(k) equal to 2.0.

  8. Use `@mtkmodel` definition blocks

    master

    An @mtkmodel definition can include several specialized begin blocks to organize the model's structure and logic:

    • @description: A String summarizing the model.
    • @parameters: Declares symbolic parameters. Variables can have initial values (e.g., p = 1.0) and metadata.
    • @variables: Declares unknowns. Variables must be functions of an independent variable (e.g., x(t)).
    • @constants: Declares values that cannot be changed by the user.
    • @structural_parameters: Declares non-symbolic inputs (like booleans or functions) that influence how the model is defined. Unlike parameters, default values here are reflected in the keyword argument list.
    • @components: Lists sub-components. Supports list comprehensions and loops. Arguments are promoted as subcomponent_name__argname.
    • @equations: The list of equations defining the system.
    • @defaults: Passes default values to the system using key => value pairs.
    • @metadata: Assigns key-value pairs as model-level metadata. Keys should be DataType to avoid collisions.
    • @icon: Embeds an icon via URI, file path, or inlined SVG.
    • @continuous_events: Defines continuous events using the condition => affect syntax.
    • @discrete_events: Defines discrete events using the condition => affect syntax, where the condition is a boolean expression.
    • @extend: Extends a base system into the current model.
    • begin ... end: Allows arbitrary Julia operations within the model definition.
    @mtkmodel ModelA begin
        @description "A component with parameters k and k_array."
        @parameters begin
            k
            k_array[1:2]
        end
    end
  9. Use analysis points to connect signals for linearization

    master

    When connecting input signals to a model, use analysis points (e.g., :u, :d1). This allows you to treat these connections as symbolic attachment points. This is critical for:

    1. Linearization: You can linearize the model as if the signals were not connected (unbound inputs).
    2. Function Generation: You can generate a Julia function for the dynamics in the form f(x, u, p, t, w), where u (control) and w (disturbances) are separate arguments, effectively treating the signals as external inputs.
    using ControlSystemsBase, ControlSystemsMTK
    # Linearize the model from inputs (u, d1, d2) to outputs (inertia velocities)
    P = named_ss(model, [ssys.u, ssys.d1, ssys.d2],
        [ssys.system_model.inertia1.w, ssys.system_model.inertia2.w])
    bodeplot(P, plotphase = false)
  10. Model disturbances using dynamical systems

    master

    There is no dedicated 'disturbance library', but you can model any disturbance with a rational spectrum using standard blocks from the Blocks module.

    Commonly used blocks for disturbance modeling include:

    • Integrator: Suitable for low-frequency components (e.g., slowly drifting signals).
    • TransferFunction: For frequency-domain specifications.
    • StateSpace: For general linear dynamical systems.

    For complex filter design (highpass, lowpass, bandpass), it is recommended to use ControlSystems.jl or ControlSystemsMTK.jl to design the system and then integrate it into your MTK model.

  11. How AnalysisPoints work for linear analysis

    master

    Linear analysis in ModelingToolkit involves linearizing a nonlinear model and analyzing the resulting linear dynamical system. This is facilitated by the AnalysisPoint concept. An AnalysisPoint acts as a causal junction (like an arrow in a block diagram) inserted between components.

    Analysis points can be created in two ways:

    1. Explicitly: Using the AnalysisPoint constructor.
    2. Automatically: By providing a name as the middle argument in a connect call.

    Important: Causality Analysis points are causal. The order of arguments in connect determines the direction of information flow. connect(out, :name, in) is different from connect(in, :name, out).

  12. Compare ModelingToolkit.jl with Causal.jl

    master

    ModelingToolkit.jl is an acausal modeling environment, while Causal.jl is a causal modeling environment.

    Key differences:

    • System Promotion: In Causal.jl, connecting different types (e.g., an SDE driving an ODE) uses different solver methods in tandem. In ModelingToolkit.jl, such connections promote the entire system to an SDE, which can improve accuracy and stability at the potential cost of performance.
    • Algebraic Loops: Causal.jl breaks algebraic loops using inexact heuristics (similar to Simulink). ModelingToolkit.jl treats algebraic loops exactly by including them as algebraic equations in the generated model.