Skip to content

Transient Analysis

The TransientAnalysis is used to simulate a component over a given time interval. For this analysis, the user defines an initial value problem (IVP) with a time interval to simulate and the transient analysis returns artifacts which describe the solution trajectory of the system.

Method Overview

The Dyad compiler uses the physical description of the system to generate a system of differential-algebraic equations:

x=f(x,y,p,t)0=g(x,y,p,t)

where x are the differential variables, y are the algebraic variables, p are the parameters, and t is the independent variable (time). This system is solved with an initial condition (x(t0),y(t0)) such that:

0=h(x(t0),y(t0),p,t0)

where h is the initialization function (built from the relations marked initial). This initial value problem is then solved over a time interval from t0 (the start time) to tf (the stop time) using a DAE solver. If the algebraic equations are trivial, i.e. g is nothing and there are not algebraic variables, then this is an ODE and it is treated via an ODE solver.

Example Definition

For this example we will run a transient analysis on the component DeSauty from the ElectricalComponents standard library. A basic usage of the transient analysis sets a run-specific parameters and time interval is given as follows:

dyad
analysis MyTransientAnalysis
  extends TransientAnalysis(start = 0, stop = 1e-3)
  parameter C::Conductance = 30e-6
  model = ElectricalComponents.DeSauty(C₁ = C)
end

The Dyad compiler will generate the MyTransientAnalysis function that will run the analysis.

julia
result = MyTransientAnalysis()
Transient Analysis Solution for TransientAnalysis
retcode: Success
Interpolation: 3rd order Hermite
t: 16-element Vector{Float64}:
 0.0
 1.0e-6
 1.586795936450487e-6
 7.454755300955357e-6
 2.28115432997575e-5
 4.5664104448907174e-5
 7.651106128366515e-5
 0.00011836165460786049
 0.0001727101289840257
 0.00024226131134568842
 0.0003294888857079311
 0.0004383985383000816
 0.0005747975715449812
 0.0007483524114999508
 0.00097303843348701
 0.001
u: 16-element Vector{Vector{Float64}}:
 [0.0, 0.0]
 [-2.923820899891337e-6, -0.00017511050717338244]
 [-7.347382279861189e-6, -0.00027710640828700934]
 [-0.00015923569257947438, -0.0012669182617594144]
 [-0.0014230120785277591, -0.003614635515402228]
 [-0.005330345933874919, -0.0065400498003263885]
 [-0.013712472833941782, -0.009615852490729606]
 [-0.02933712753910297, -0.012589684835191446]
 [-0.05456302521738237, -0.015047506091293622]
 [-0.09169025462020348, -0.016783167056749024]
 [-0.14213061212383468, -0.017756962170787358]
 [-0.20738685163523904, -0.018087139454824725]
 [-0.2893823819109583, -0.01791257448531749]
 [-0.3913426476626362, -0.01728306433626297]
 [-0.5165378314750091, -0.01608841469422157]
 [-0.5309222101075886, -0.015921651811767683]

We can plot this result, using either Plots.jl or Makie.jl. We'll use Plots here:

julia
using Plots
Plots.plot(result)

Analysis Arguments

The following arguments define a TransientAnalysis:

Required Arguments

  • model: the Dyad model that the analysis is being applied to.

  • stop::Time: chooses the end time for the interval.

Optional Arguments

  • alg::String: chooses the solver algorithm for the solution process. The default is "auto". The choices are:

    • "auto" - Automatic algorithm choice with stiffness detection, size detection, and linear solve swapping from OrdinaryDiffEq.jl.

    • "Rodas5P" - Adaptive time Rosenbrock method from OrdinaryDiffEqRosenbrock.jl. The Rosenbrock methods are specifically fast for small systems of stiff equations and DAEs which avoid Jacobian singularity issues (i.e. no variable-index DAE behavior).

    • "FBDF" - Adaptive order, adaptive time fixed leading coefficient backwards differentiation formulae (BDF) method from OrdinaryDiffEqBDF.jl, modeled after the FLC formulation of VODE. This is a good method for large stiff systems and DAEs.

    • "Tsit5" - 5th order explicit Runge-Kutta method from OrdinaryDiffEqTsit5.jl. This method is not applicable to DAEs and is only applicable to systems which have no algebraic constraints (post simplification).

  • start::Time: chooses the start time for the interval. Defaults to 0.

  • abstol::Real: chooses the absolute tolerance for the solver. Defaults to 1e-6.

  • reltol::Real: chooses the relative tolerance for the solver. Defaults to 1e-3.

  • saveat::Real: chooses the saving interval for the solving process. The default is 0, which corresponds to saving a dense output with a continuous time interpolation for high-fidelity solution at all points. If a non-zero value is chosen, for example, 0.1, then it will save at only the interval points (0.1, 0.2, ...) and use a linear interpolation between those points. This should only be used as a performance and memory optimization.

  • dtmax::Time: sets the dtmax of the ODE solver. Defaults to 0 which uses the default of the solver. Setting this lower can be used to force smaller steps and thus a more accurate solution.

Experimental Arguments

  • IfLifting::Boolean: sets the iflifting compiler pass in the ModelingToolkit code generation. Currently defaults to false, but will default to true after the feature is made non-experimental.

Artifacts

A TransientAnalysis returns the following artifacts:

Customizable Plot

The customizable plot of a TransientAnalysis is the timeseries plot of the ODE/DAE solve which satisfies the rules and definitiosn of the DifferentialEquations.jl plotting interface.

Standard Plots

  • :SimulationSolutionPlot: Returns the standard time series plot of the solution trajectory for all values in the state vector.

Tables

  • :SimulationSolutionTable: Returns a DataFrame of the solution. If saveat=0, then the t are the adaptively chosen points, otherwise the t matches the interval chosen by saveat.

Julia-Side Artifacts

  • :RawSolution: Returns the DifferentialEquations.jl solution type from the run.

  • :SimplifiedSystem: Returns the ModelingToolkit.jl model after structural simplification was performed.

  • :InitialSystem: Returns the initial ModelingToolkit.jl model that was passed to the analysis.

Special Julia-Side Interactivity

The TransientAnalysis includes special Julia-side behaviors for better analyzing the time series of solutions. In particular, if you do:

julia
result = MyTransientAnalysis(; #= kwargs... =#)
Transient Analysis Solution for TransientAnalysis
retcode: Success
Interpolation: 3rd order Hermite
t: 16-element Vector{Float64}:
 0.0
 1.0e-6
 1.586795936450487e-6
 7.454755300955357e-6
 2.28115432997575e-5
 4.5664104448907174e-5
 7.651106128366515e-5
 0.00011836165460786049
 0.0001727101289840257
 0.00024226131134568842
 0.0003294888857079311
 0.0004383985383000816
 0.0005747975715449812
 0.0007483524114999508
 0.00097303843348701
 0.001
u: 16-element Vector{Vector{Float64}}:
 [0.0, 0.0]
 [-2.923820899891337e-6, -0.00017511050717338244]
 [-7.347382279861189e-6, -0.00027710640828700934]
 [-0.00015923569257947438, -0.0012669182617594144]
 [-0.0014230120785277591, -0.003614635515402228]
 [-0.005330345933874919, -0.0065400498003263885]
 [-0.013712472833941782, -0.009615852490729606]
 [-0.02933712753910297, -0.012589684835191446]
 [-0.05456302521738237, -0.015047506091293622]
 [-0.09169025462020348, -0.016783167056749024]
 [-0.14213061212383468, -0.017756962170787358]
 [-0.20738685163523904, -0.018087139454824725]
 [-0.2893823819109583, -0.01791257448531749]
 [-0.3913426476626362, -0.01728306433626297]
 [-0.5165378314750091, -0.01608841469422157]
 [-0.5309222101075886, -0.015921651811767683]

then artifacts(result, :RawSolution) gives you the DifferentialEquations.jl solution type from the run. Thus for example:

julia
using DyadInterface: artifacts
sol = artifacts(result, :RawSolution)
retcode: Success
Interpolation: 3rd order Hermite
t: 16-element Vector{Float64}:
 0.0
 1.0e-6
 1.586795936450487e-6
 7.454755300955357e-6
 2.28115432997575e-5
 4.5664104448907174e-5
 7.651106128366515e-5
 0.00011836165460786049
 0.0001727101289840257
 0.00024226131134568842
 0.0003294888857079311
 0.0004383985383000816
 0.0005747975715449812
 0.0007483524114999508
 0.00097303843348701
 0.001
u: 16-element Vector{Vector{Float64}}:
 [0.0, 0.0]
 [-2.923820899891337e-6, -0.00017511050717338244]
 [-7.347382279861189e-6, -0.00027710640828700934]
 [-0.00015923569257947438, -0.0012669182617594144]
 [-0.0014230120785277591, -0.003614635515402228]
 [-0.005330345933874919, -0.0065400498003263885]
 [-0.013712472833941782, -0.009615852490729606]
 [-0.02933712753910297, -0.012589684835191446]
 [-0.05456302521738237, -0.015047506091293622]
 [-0.09169025462020348, -0.016783167056749024]
 [-0.14213061212383468, -0.017756962170787358]
 [-0.20738685163523904, -0.018087139454824725]
 [-0.2893823819109583, -0.01791257448531749]
 [-0.3913426476626362, -0.01728306433626297]
 [-0.5165378314750091, -0.01608841469422157]
 [-0.5309222101075886, -0.015921651811767683]
julia
sol(1.0)
2-element Vector{Float64}:
 -5.370930557667406e9
  1.0124597660934585e9

For more information on using the solution object, see the DifferentialEquations.jl solution interface for more information. This solution allows for using the DifferentialEquations.jl plotting interface, for example:

julia
using Plots
plot(sol)

See the DifferentialEquations.jl plotting documentation for more details. Note that for convenience, the original result object can be plotted directly without rebuilding the solution:

julia
plot(result)

Further Reading