Differential-Algebraic Equations (DAE)
A (parametrised) differential-algebraic equation (DAE) is written as
\[M(x, p)\cdot \dot x = F(x, p),\]
where $x \in \mathbb R^{n}$ is the state, $p$ the parameters and $M(x, p)$ is the mass matrix (possibly singular for index-1 DAEs). Denoting by $x_{eq}$ an equilibrium, i.e. a solution of the algebraic system $F(x_{eq}, p) = 0$, the dynamics around $x_{eq}$ is governed by the generalized eigenproblem
\[J(x_{eq}, p)\cdot v = \lambda\, M(x_{eq}, p)\cdot v,\qquad J \equiv d_xF,\]
so that stability is decided by the generalized eigenvalues $(\lambda)$. More details on the generalized eigen solvers are given on the page eigensolver.md (section Generalized eigen problem).
Functionalities and support
The following table summarises which functionalities are supported depending on the type of mass matrix. A constant mass matrix is independent of $(x, p)$ (it can be singular, i.e. index-1); a non-constant one depends on the state / parameters, $M = M(x,p)$.
| Functionality | Constant $M$ | Non-constant $M(x,p)$ |
|---|---|---|
| Equilibrium continuation & Newton | ✔ | ⚠ partial |
| Stability — generalized eigenvalues $(J, M)$ | ✔ | ⚠ partial |
Fold / Hopf location & refinement (newton_fold, newton_hopf) | ✔ | ✘ |
Hopf normal form (hopf_normal_form) | ✔ | ✘ |
| Codim 2 curves of Fold / Hopf + BT / Cusp detection | ✔ | ✘ |
| Detailed codim 2 normal forms (BT, Cusp, Bautin, ZH, HH) | ✘ | ✘ |
Periodic orbits — Shooting (SciML mass_matrix) | ✔ | ⚠ |
Periodic orbits — Trapeze + massmatrix | ✔ (dense Floquet; matrix-free in progress) | ✘ |
Here ✔ means supported, ⚠ means only partially supported (the mass matrix is evaluated once at the current solution and its derivatives are not taken into account), and ✘ means not supported (a clear error is raised).
Wrapping a problem with a mass matrix
The equilibrium machinery of BifurcationKit acts on BifurcationProblem (or ODEBifProblem) and treats the case $M = I$ (identity). A problem with a general mass matrix is encoded with BifurcationKit.DAEMassBifProblem which wraps an ODEBifProblem together with the mass matrix $M$:
prob = ODEBifProblem(F, u0, params, (@optic _.μ))daeprob = BifurcationKit.DAEMassBifProblem(prob, Mass)The mass matrix $M$ can be
- a constant matrix, e.g.
M = [1. 0; 0 0.](or a sparse matrix), - a
UniformScaling(e.g.LA.I,α * LA.I): it is then represented by the markerBifurcationKit.IdentityOperator, - a function $M(x, p)$: this case is only partially supported (basically only simple continuation).
The kind of mass matrix (constant vs. state dependent) is tracked by the first type parameter, BifurcationKit.ConstantMass being the default for constant matrices. Useful accessors are
| call | role |
|---|---|
BifurcationKit.getmassmatrix(pb, x, p) | evaluate the mass matrix |
BifurcationKit.is_mass_matrix_constant(pb) | is the mass matrix constant? |
re_make(pb; M = newMass, u0 = …) | rebuild with another mass matrix |
A small example
We consider the (polynomial) Stuart-Landau model with the invertible constant mass matrix $M = \mathrm{diag}(2, 1)$:
using BifurcationKit, LinearAlgebra# the vector field F(x, p)function Fsl2(x, p) (; r, μ, ν, c3) = p u1, u2 = x ua = u1^2 + u2^2 return [r * u1 - ν * u2 - ua * (c3 * u1 - μ * u2), r * u2 + ν * u1 - ua * (c3 * u2 + μ * u1)]endpar_sl = (r = -0.1, μ = 0.132, ν = 1.0, c3 = 1.123)# constant (diagonal) mass matrixMass = Diagonal([2.0, 1.0])prob = ODEBifProblem(Fsl2, zeros(2), par_sl, (@optic _.r))daeprob = BifurcationKit.DAEMassBifProblem(prob, Mass)# continuation with detection of the Hopf bifurcationopts = ContinuationPar(ds = 0.01, dsmax = 0.02, dsmin = 1e-3, p_min = -0.3, p_max = 0.1)br = continuation(daeprob, PALC(), opts; verbosity = 0, normC = norminf)ind_h = findfirst(pt -> pt.type == :hopf, br.specialpoint)println("Hopf point located at r = ", br.specialpoint[ind_h].param)# Hopf normal form (mass matrix handled with the bordered vectors)hp = BifurcationKit.hopf_normal_form(daeprob, br, ind_h; start_with_eigen = Val(false))SuperCritical - Hopf bifurcation point at r ≈ 0.0025304832720493943.
Frequency ω ≈ 0.707106498195923
Period of the periodic orbit ≈ 8.885769432483224
Normal form z⋅(iω + a⋅δr + b⋅|z|²):
┌─ a = 0.7501306142085112 + 0.0026456405718140036im
└─ b = -1.779281890508023 + 0.17790736989586187im
Note that the eigenvalue / stability computation during continuation is performed on the pencil $(J, M)$, the eigen solver being automatically wrapped into BifurcationKit.EigenDAE when the problem is a DAEMassBifProblem.
Bifurcations points and normal forms
- Fold / Hopf points of the DAE are located and refined with the usual
newton_fold/newton_hopf(Minimally Augmented formulation), the bordered systems now involving the mass matrix (e.g. $(J - i\omega M)$ for the Hopf problem). - The Hopf normal form is available through
get_normal_form. Onlystart_with_eigen = Val(false)is supported for a mass matrix (the eigen-computation would otherwise ignore $M$): the right/left eigenvectors are obtained by solving bordered linear systems on the pencil $(J, M)$ and the left one is normalized by $\langle \zeta^\star, M \zeta\rangle = 1$. - Codimension 2: the continuation of Fold / Hopf curves (2 parameters) and the detection of codim 2 points (BT, Cusp, Bautin, …) work for a constant mass matrix. The detailed codim 2 normal forms (e.g. for the Bogdanov-Takens point) are however not implemented yet for problems with a mass matrix and raise an error.
Periodic orbits of DAEs
Periodic orbits of a DAE can be tackled in two ways:
- Shooting the underlying SciML
ODEProblemwith amass_matrixoption, see the tutorial Colpitts-type oscillator (Tutorials → DAE examples). - Finite differences with the
Trapezediscretization equipped with amassmatrix, see the pageperiodicOrbitTrapeze.md.
Linear algebra internals
The shifted linear systems which appear with a mass matrix, e.g. $(a_0 M + a_1 J)\,x = b$, are encoded by wrapping the pair $(M, J)$ in a BifurcationKit.MassAndJacobian inside a BifurcationKit.ShiftedOperator. Both direct and iterative / matrix-free (bordered) linear solvers take this into account: see the pages linearsolver.md and borderedlinearsolver.md.
API
BifurcationKit.DAEMassBifProblem — Type
struct DAEMassBifProblem{Tkind<:BifurcationKit.AbstractDAEMassType, Tprob, TM} <: BifurcationKit.AbstractDAEBifProblemWrapper around an AbstractBifurcationProblem to encode a Differential Algebraic Equation (DAE) of the form M(x, p) * dx/dt = F(x, p), where M is a (possibly state dependent) mass matrix.
Type parameters
Tkind <: AbstractDAEMassType: kind of mass matrix,ConstantMassby default. It is set through the keywordtypeof the constructor or by usingDAEMassBifProblem{ConstantMass}(...).
Fields
prob_vf::Any: vector field, must beAbstractBifurcationProblem.M::Any: Mass matrix/operator.
Methods
getparams(pb)callsgetparams(pb.prob_vf)getlens(pb)callsgetlens(pb.prob_vf)getparam(pb)callsgetparam(pb.prob_vf)setparam(pb, p0)callssetparam(pb.prob_vf, p0)getu0(pb)callsgetu0(pb.prob_vf)residual(pb, x, p)callsresidual(pb.prob_vf, x, p)jacobian(pb, x, p)callsjacobian(pb.prob_vf, x, p)getmassmatrix(pb, x, p)returns the mass matrixM(x, p)(orpb.Mif it is a constant matrix)record_from_solution(pb),save_solution(pb, u, pars),update!(pb, iter, state)are forwarded topb.prob_vfre_make(pb; M = …, kwargs…)rebuilds the problem, possibly with another mass matrix- the jet methods of the wrapped problem (
R01,dF,d2F,d3F, …) are forwarded as well
Constructors
DAEMassBifProblem(prob, M; type = ConstantMass)wraps the bifurcation problemprobwith the mass matrixM, which can be a matrix or a functionM(x, p).DAEMassBifProblem{ConstantMass}(prob, M)explicitly sets the kind of mass matrix through the type parameter.- a
UniformScalingmass matrix (I,α * I) is also accepted: the identity case is stored with the markerIdentityOperatorso that no mass matrix solve is required.
Remark
The eigenvalues along the continuation are the generalized eigenvalues of (J(x, p), M(x, p)) where J is the jacobian of prob_vf, so that stability detection accounts for the mass matrix. During continuation, the eigen solver is automatically wrapped into EigenDAE to compute these generalized eigen-elements.
A mass matrix which depends on the state x (as opposed to a constant one, or one depending only on the parameters) is only partially supported: it is evaluated once at the current solution during continuation, but the higher order derivatives of the vector field F do not account for derivatives of M.
BifurcationKit.ConstantMass — Type
struct ConstantMass <: BifurcationKit.AbstractDAEMassTypeMarker for a constant mass matrix M (independent of the state x and of the parameters p). It is used as the default kind / first type parameter of DAEMassBifProblem.
Missing docstring for BifurcationKit.IdentityOperator. Check Documenter's build log for details.
BifurcationKit.EigenDAE — Type
struct EigenDAE{Te} <: BifurcationKit.AbstractDAEEigenSolverEigen solver wrapper for Differential Algebraic Equations of the form M⋅u' = F(u). It solves the generalized eigen problem
J(x, p)⋅v = λ⋅M(x, p)⋅vwhere J is the jacobian of the vector field and M the mass matrix, by delegating to gev(eigensolver, J, Mass, nev).
It is called as
eig(J, Mass, nev)with a matrix valued jacobian J (matrix-free / operator jacobians are not supported for the generalized problem). The identity mass marker IdentityOperator is special-cased: the call then reduces to the plain eigen solve eigensolver(J, nev).
A continuation on any DAE problem (AbstractDAEBifProblem) wraps the user-provided eigen solver into EigenDAE automatically, so that stability and bifurcation detection use the generalized eigenvalues of (J, M).
Fields
eigensolver::Any: Eigensolver.
Constructors
EigenDAE(eigensolver)wrapseigensolver(e.g.DefaultEig(),EigArpack(),EigArnoldiMethod()).EigenDAE()defaults toEigenDAE(DefaultEig()).