Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Hybrid DAE Overview

SiNDAE targets hybrid differential-algebraic equation (DAE) systems (also called Universal Differential Equations or UDEs) in which one or more constitutive relations are replaced by a trainable neural network. The notation on this page follows Lueg et al. (2025).


Problem formulation

SiNDAE considers the semi-explicit neural DAE on a horizon [t0,tf][t_0, t_f]:

dxdt=f(x(t),y(t),z(t),p),t[t0,tf]0=h(x(t),y(t),z(t),p),t[t0,tf]0=z(t)fNN(v(t),θ),t[t0,tf]x(t0)=x0(p).\begin{aligned} \frac{d\mathbf{x}}{dt} &= \mathbf{f}\bigl(\mathbf{x}(t),\, \mathbf{y}(t),\, \mathbf{z}(t),\, \mathbf{p}\bigr), && \forall t \in [t_0, t_f] \\ 0 &= \mathbf{h}\bigl(\mathbf{x}(t),\, \mathbf{y}(t),\, \mathbf{z}(t),\, \mathbf{p}\bigr), && \forall t \in [t_0, t_f] \\ 0 &= \mathbf{z}(t) - \mathbf{f}_{NN}\bigl(\mathbf{v}(t),\, \boldsymbol{\theta}\bigr), && \forall t \in [t_0, t_f] \\ \mathbf{x}(t_0) &= \mathbf{x}_0(\mathbf{p}). && \end{aligned}

The variables are the differential states x(t)Rnx\mathbf{x}(t) \in \mathbb{R}^{n_x}, the algebraic variables y(t)Rny\mathbf{y}(t) \in \mathbb{R}^{n_y} and z(t)Rnz\mathbf{z}(t) \in \mathbb{R}^{n_z}, and the independent static variables pRnp\mathbf{p} \in \mathbb{R}^{n_p}. The neural network

fNN:Rnv+nθRnz,θRnθ,\mathbf{f}_{NN} : \mathbb{R}^{n_v + n_\theta} \mapsto \mathbb{R}^{n_z}, \qquad \boldsymbol{\theta} \in \mathbb{R}^{n_\theta},

supplies the unknown terms z(t)\mathbf{z}(t) from a chosen subset of the remaining variables, its inputs v(t)Rnv\mathbf{v}(t) \in \mathbb{R}^{n_v} with v(t){x(t),y(t),p}\mathbf{v}(t) \subseteq \{\mathbf{x}(t),\, \mathbf{y}(t),\, \mathbf{p}\}. Domain knowledge defines this structural prior, that is, which variables enter v(t)\mathbf{v}(t). The maps f:Rnx+ny+nz+npRnx\mathbf{f} : \mathbb{R}^{n_x + n_y + n_z + n_p} \mapsto \mathbb{R}^{n_x} and h:Rnx+ny+nz+npRny\mathbf{h} : \mathbb{R}^{n_x + n_y + n_z + n_p} \mapsto \mathbb{R}^{n_y} (and fNN\mathbf{f}_{NN}) are assumed Lipschitz continuous on [t0,tf][t_0, t_f] once p\mathbf{p} and θ\boldsymbol{\theta} are fixed. The initial differential state may depend on p\mathbf{p}; if it is unknown it can be absorbed into p\mathbf{p}.

In the SiNDAE API this maps onto a ProblemDefinition as follows: f\mathbf{f} and h\mathbf{h} are the differential and algebraic constraints written in build_trajectory, the network inputs v(t)\mathbf{v}(t) are returned by get_input_vars, the network outputs z(t)\mathbf{z}(t) by get_output_vars, and fNN\mathbf{f}_{NN} is a SimpleMLP (or any compatible module).

Differential index

Substituting the network relation into the other equations gives the algebraic constraint

0=h(x(t),y(t),fNN(x(t),θ),p).0 = \mathbf{h}\bigl(\mathbf{x}(t),\, \mathbf{y}(t),\, \mathbf{f}_{NN}(\mathbf{x}(t), \boldsymbol{\theta}),\, \mathbf{p}\bigr).

For a given p\mathbf{p} and θ\boldsymbol{\theta}, if yh\nabla_{\mathbf{y}} \mathbf{h} is nonsingular for all t[t0,tf]t \in [t_0, t_f], the DAE is index-1. Otherwise the index is the minimum number of differentiations of the algebraic constraints required to obtain ODEs for the algebraic variables y(t)\mathbf{y}(t), exactly as for conventional DAEs Biegler (2010). SiNDAE places no restriction on the index; the four-tank example is index-2.

Data and training objective

The training data come from a set of trajectories, or scenarios, S={1,,ns}\mathcal{S} = \{1, \dots, n_s\}. The network outputs z(t)\mathbf{z}(t) are usually unobserved; instead we observe the variables that define the network input, which for the problems considered here are the differential states x(t)\mathbf{x}(t), sampled at times tiTost_i \in \mathcal{T}_o^s. Writing xˉ(s)(t)\bar{\mathbf{x}}^{(s)}(t) for the ground-truth trajectory of scenario ss, the observations are

x^i(s)=xˉ(s)(ti)+ϵi(s),sS, tiTos,\hat{\mathbf{x}}_i^{(s)} = \bar{\mathbf{x}}^{(s)}(t_i) + \boldsymbol{\epsilon}_i^{(s)}, \qquad \forall s \in \mathcal{S},\ \forall t_i \in \mathcal{T}_o^s,

with zero-mean Gaussian observation noise ϵi(s)\boldsymbol{\epsilon}_i^{(s)}. The data-fit loss for a continuous state profile x(s)(t)\mathbf{x}^{(s)}(t) on scenario ss is

φ(s)(x(s)(t))=tiTosx(s)(ti)x^i(s)22.\varphi^{(s)}\bigl(\mathbf{x}^{(s)}(t)\bigr) = \sum_{t_i \in \mathcal{T}_o^s} \bigl\| \mathbf{x}^{(s)}(t_i) - \hat{\mathbf{x}}_i^{(s)} \bigr\|_2^2 .

Training minimizes sSφ(s)\sum_{s \in \mathcal{S}} \varphi^{(s)} over the network parameters θ\boldsymbol{\theta} together with the state and algebraic trajectories, subject to the neural DAE above. SiNDAE solves this either jointly as a single NLP (the simultaneous approach) or with an outer loop over θ\boldsymbol{\theta} around inner DAE solves (the decomposition approach).


Collocation discretization

The continuous neural DAE is discretized with Lagrange-Radau collocation on a mesh of NfeN_{fe} finite elements with NcpN_{cp} collocation points each. This replaces the differential and algebraic constraints with a finite set of algebraic equations, turning the training problem into a finite-dimensional NLP. Following the paper, a discretized variable at collocation index kk on scenario ss is written xk(s)\mathbf{x}_k^{(s)}.

Pyomo’s dae.collocation transformation performs the symbolic discretization; ProblemDefinition.discretize calls it by default.


Defining your own problem

Subclass ProblemDefinition and implement three abstract methods. build_trajectory writes f\mathbf{f} and h\mathbf{h} and fixes the initial conditions; get_input_vars returns v(t)\mathbf{v}(t); get_output_vars returns z(t)\mathbf{z}(t).

from sindae.problem import ProblemDefinition
import pyomo.dae as dae
import pyomo.environ as pyo

class MyProblem(ProblemDefinition):
    def build_trajectory(self, block, traj_idx):
        """Declare Pyomo Var, DerivativeVar, and constraints (no NN yet)."""
        block.t    = dae.ContinuousSet(bounds=self.t_span)
        block.x    = pyo.Var(block.t, range(2), initialize=1.0)
        block.z    = pyo.Var(block.t, range(1))
        block.dxdt = dae.DerivativeVar(block.x, wrt=block.t)

        @block.Constraint(block.t)
        def ode(b, t):
            return b.dxdt[t, 0] == -b.x[t, 0] + b.z[t, 0]

        block.x[self.t_span[0], 0].fix(self.ics[traj_idx, 0])

    def get_input_vars(self, block, t):
        """Network inputs v(t) at time t."""
        return [block.x[t, j] for j in range(2)]

    def get_output_vars(self, block, t):
        """Network outputs z(t) at time t."""
        return [block.z[t, 0]]

Optionally override:

MethodDefaultPurpose
get_obs_varssame as get_input_varsObserved variables in the data-fit objective φ(s)\varphi^{(s)}
get_aux_varsemptyExtra variables to record in InstanceData
discretizeRadau collocationOverride for custom schemes
add_true_output_constraintsNotImplementedErrorTrue formula for z(t)\mathbf{z}(t), used only by generate_data

See Problem Definition for the full API.


Smoother pre-step

Before training the network, SiNDAE solves a smoother NLP that:

  1. Fits a smooth state profile to the noisy observations x^i(s)\hat{\mathbf{x}}_i^{(s)}.

  2. Produces initial values for x(t)\mathbf{x}(t) and z(t)\mathbf{z}(t) to warm-start the training NLP.

  3. Computes the normalization statistics (mean and standard deviation) for the network inputs v(t)\mathbf{v}(t) and outputs z(t)\mathbf{z}(t).

The smoother penalizes z˙smooth2\|\dot{\mathbf{z}}_\text{smooth}\|^2 weighted by smooth_coef. A larger smooth_coef yields smoother but potentially less data-faithful z\mathbf{z} estimates.

See Smoother and sindae.algorithms.smoother.solve_smoother.


Built-in example problems

sindae.example_problems ships three benchmark systems:

ClassSystemDAE index
FourTankProblemFour-tank hydraulic network (4 differential, 5 algebraic, nz=2n_z = 2)2
LeslieGowerProblemPredator-prey ODE (2 differential, nz=1n_z = 1)ODE
FedBatchBioreactorProblemFed-batch bioreactor with Monod kinetics (4 differential, nz=1n_z = 1)ODE
References
  1. Lueg, L. R., Alves, V., Schicksnus, D., Kitchin, J. R., Laird, C. D., & Biegler, L. T. (2025). A simultaneous approach for training neural differential-algebraic systems of equations. arXiv Preprint arXiv:2504.04665. https://arxiv.org/abs/2504.04665
  2. Biegler, L. T. (2010). Nonlinear Programming: Concepts, Algorithms, and Applications to Chemical Processes.