\[ \def\F{{\color{#ff7f0e} F}} \def\u{{\color{#1f77b4} u}} \def\hu{{\color{#2ca02c} \hat{u}}} \def\bN{\boldsymbol{N}} \def\bQ{\boldsymbol{Q}} \def\bq{\boldsymbol{q}} \def\bV{\boldsymbol{V}} \def\bo{\boldsymbol{o}} \def\bx{\boldsymbol{x}} \def\bv{\boldsymbol{v}} \def\bu{\boldsymbol{u}} \def\bzero{\boldsymbol{0}} \]

Some Notation for External Operators#

This document outlines the notation and discrete tensor calculus conventions used when working with external operators in FEniCSx. It bridges directional derivatives with complex variational formulations, particularly those involving multiple arguments, nested compositions, high-order tensors, and mixed function spaces. Ultimately, these conventions aim to help users systematically formulate, linearize, and understand variational problems involving external operators.

The Directional Derivative of a Variational Form#

In standard finite element analysis, the weak form of a nonlinear boundary value problem is expressed as finding \(\u \in V\) such that for all test functions \(v \in \hat{V}\):

\[ \F(\u; v) = 0 \]

To solve this nonlinear system using Newton-like methods, we must linearize the form. This requires computing the Gâteaux derivative (or directional derivative) of the \({ \color{#ff7f0e}\text{functional }} \F\) at the \({ \color{#1f77b4}\text{argument }}\u\) in the \({ \color{#2ca02c}\text{direction }} \hu \in V\):

\[ D_\u { [\F]} { \{ \hu \} }= \lim_{\epsilon \to 0} \frac{\F(\u + \epsilon \hu; v) - \F(\u; v) }{\epsilon}, \]

We refer to this derivative as the Jacobian of \(\F\) and denote it as:

\[ J(\u ; \hu, v) := D_\u[\F(\u ; v)]\{ \hu \}, \]

where the semicolon (\(;\)) separates the non-linear (left) and linear (right) operands of \(J\) (similar to \(\F\)).

Note

Although this notation may look verbose, in the presence of functionals with multiple arguments and compositions (see the chain rule below), it clarifies the expression of derivatives for complex variational forms (see examples below).

Chain rule#

If \(\F\) depends on an intermediate operator \(N(\u)\) (also known as an external operator), the derivative expands via the chain rule:

\[ D_\u[\F \circ N(\u)]\{ \hu \} = D_\u[\F(N(\u); v)]\{ \hu \} = D_N[\F]\{ D_\u[N] \{ \hu \} \} \]

Then the Jacobian can be defined as

\[ J(\u ; \hat{N}, v) = D_N[\F] \{ \hat{N} \}, \]

where the direction \(\hat{N} = D_\u[N] \{ \hu \}\) is itself a directional derivative of the operator \(N\) in the direction \(\hu\).

If the functional \(\F\) depends on multiple nonlinear operands, we distinguish between total (\(D_\cdot[\cdot]\{ \cdot \}\)) and partial Gâteaux (\(\partial_\cdot[\cdot]\{ \cdot \}\)) derivatives to clarify which argument the directional derivative is taken with respect to. For example:

\[ D_\u[\F(\u, w, N(\u); v)]\{ \hu \} = \partial_\u [\F(\u, w, N(\u); v)]\{ \hu \} + \partial_N [\F(\u, w, N(\u); v)]\{ \hat{N} \}, \]

where \(\hat{N} = D_\u[N] \{ \hu \}\).

The Derivative of the External Operator#

The external operator \(N\) may itself depend on an operand \(o(\u)\), thus we apply the chain rule again:

\[ D_\u[N(o(\u))]\{ \hu \} = \frac{\partial N}{\partial o} \cdot D_\u [o(\u)]\{ \hu \}. \]

Thus, the Gâteaux derivative of \(N\) consists of two parts:

  1. The partial derivative of \(N\) with respect to its operand: \(\frac{\partial N}{\partial o}\). This part can be treated as a standard derivative of \(N\). This is exactly what we mean by the “derivative of an external operator”, which is itself a new external operator and must be explicitly provided by the user in the form of a program that computes the values of \(\frac{\partial N}{\partial o}\).

  2. The second part represents the derivative of an expression that depends on the main field \(\u\) (typically a UFL expression like \(\nabla \u\)). This part is handled automatically by UFL, except when the operand \(o(\u)\) is another external operator.

An external operator may, of course, depend on multiple operands (e.g., \(o_1\), \(o_2\), and \(o_3\)), which in turn may depend on multiple main fields (e.g., \(\u\), \(w\)):

\[ D_\u[N(o_1(\u), o_2(w), o_3(\u))]\{ \hu \} = \frac{\partial N}{\partial o_1} \cdot D_\u [o_1(\u)]\{ \hu \} + \frac{\partial N}{\partial o_3} \cdot D_\u [o_3(\u)]\{ \hu \}. \]

The General Tensor Case#

To ensure dimensional consistency and generalize the external operator framework, we must define the tensor ranks and contraction rules explicitly.

Let the external operator \(\bN(\bo(\u))\) be a tensor function of rank \(k\). Let its input argument, the operator \(\bo(\u)\), be a tensor of rank \(p\). Then, the derivative of the external operator (also known as the tangent operator \(\mathbb{C}\))

\[ \mathbb{C} := \frac{\partial \bN}{\partial \bo} \]

is a higher-order tensor of rank \(k + p\).

When the external operator is varied in the direction \(\hu\), the resulting directional derivative is a contraction of tensors:

\[ D_\u[\bN(\bo(\u))]\{ \hu \} = \mathbb{C} : D_\u [\bo(\u)] \{ \hu \} \]

Explicit Index Notation#

Using the Einstein summation convention, let \(\alpha_1 \dots \alpha_k\) denote the indices of the external operator \(\boldsymbol{N}\), and \(\beta_1 \dots \beta_p\) denote the indices of the operand \(\boldsymbol{o}\).

The components of the tangent tensor \(\mathbb{C}\) are:

\[\mathbb{C}_{\alpha_1 \dots \alpha_k \beta_1 \dots \beta_p} = \frac{\partial \boldsymbol{N}_{\alpha_1 \dots \alpha_k}}{\partial \boldsymbol{o}_{\beta_1 \dots \beta_p}}\]

The directional variation of the external operator is evaluated by contracting the tangent tensor \(\mathbb{C}\) with the directional variation of operand \(\bo\) over the \(p\) indices of the latter:

\[ \left(D_u[\boldsymbol{N}(\boldsymbol{o}(u))]\{ \hat{u} \}\right)_{\alpha_1 \dots \alpha_k} = \mathbb{C}_{\alpha_1 \dots \alpha_k \beta_1 \dots \beta_p} : (D_u [\boldsymbol{o}(u)] \{ \hat{u} \})_{\beta_1 \dots \beta_p} \]

Mixed-element external operators#

Let’s assume that the external operator \(\boldsymbol{N}\) is from a mixed element space \(V\) which consists of \(m\) subspaces:

\[ V = V_1 \times \cdots \times V_m, \]

so the external operator is represented as a block object

\[ \boldsymbol{N} = (\boldsymbol{N}_1, \dots, \boldsymbol{N}_m), \]

where each “sub” external operator is from the corresponding subspace: \(\boldsymbol{N}_i \in V_i\).

Note

Although there are independent “sub” external operators, their values are stored in a single flattened vector, preserving the order with respect to the component subspaces. See examples in test_mixed_element_space: a-latyshev/dolfinx-external-operator.

If the external operator has multiple operands \(\boldsymbol{N} = \boldsymbol{N}(\boldsymbol{o}_1, \dots, \boldsymbol{o}_n)\), its derivative may require the allocation of new function spaces due to the change of the mathematical shape. For example, let’s consider the partial derivative of \(\bN\) with respect to a certain operand \(\bo_j\):

\[ \frac{\partial \boldsymbol{N}}{\partial \boldsymbol{o}_j} = \left( \frac{\partial \boldsymbol{N}_1}{\partial \boldsymbol{o}_j}, \dots, \frac{\partial \boldsymbol{N}_m}{\partial \boldsymbol{o}_j} \right), \quad j = 1, \dots,n. \]

If \(\boldsymbol{N}_i\) is a tensor of rank \(k_i\) and the operand \(\boldsymbol{o}_j\) has the rank \(p_j\), then \(\mathrm{rank}\left( \frac{\partial \boldsymbol{N}_i}{\partial \boldsymbol{o}_j}\right) = k_i + p_j\). These new derivatives \(\frac{\partial \boldsymbol{N}_i}{\partial \boldsymbol{o}_j}\) must live in new function spaces \(Q_{ij}\) with appropriate dimensions. dolfinx-external-operator is designed to automatically create the final mixed-element space \(Q_{j}\) composed of \(Q_{ij}\), where the derivative \(\frac{\partial \boldsymbol{N}}{\partial \boldsymbol{o}_j}\) lives:

\[ \frac{\partial \boldsymbol{N}}{\partial \boldsymbol{o}_j} \in Q_j = Q_{1j} \times \cdots \times Q_{mj}, \quad j = 1, \dots,n. \]

Important

The creation of a function space is an expensive operation. When external operators and their operands are higher-order tensors, substantial memory may be allocated automatically.

Example:

Let’s suppose that the external operator \(\bN\) is from the mixed function space \(\bV = V_1 \times \bV_2\), consisting of two subspaces: a scalar space \(V_1\) and a vector space \(\bV_2\) in \(\mathbb{R}^2\). Furthermore, \(\bN\) depends on two operands \(o_1(\cdot) \in V_1\) and \(\bo_2(\cdot) \in \bV_2\):

\[ \bN(o_1, \bo_2) = (N_1(o_1, \bo_2), \bN_2(o_1, \bo_2)) \in \bV = V_1 \times \bV_2\]

Here for simplicity we consider the following operands:

\[ o_1 = o_1(u_1), \quad \bo_2 = \bo_2(\bu_2) \]

For \(\bu, \bv \in \bV\)

\[ F(N_1, \bN_2;\bv) = \int\limits_\Omega N_1 v_1 + \bN_2 \cdot \bv_2 \, \mathrm{d}\bx \]

For the trial function \(\hat{\bu} = (\hat{u}_1, \hat{\bu}_2) \in \bV\) from the mixed element space, the directional derivative is as follows:

\[ D_{\bu}[F]\{\hat{\bu}\} = D_{u_1}[F]\{ \hat{u}_1 \} + D_{\bu_2}[F] \{ \hat{\bu}_2 \}, \]

where, keeping in mind \(F = F(N_1(o_1, \bo_2), \bN_2(o_1, \bo_2);\bv)\), we expand each term:

\[ D_{u_1}[F]\{ \hat{u}_1 \} = \partial_{N_1}[F]\{ D_{u_1}[N_1]\{ \hat{u}_1 \} \} + \partial_{\bN_2}[F]\{ D_{u_1}[\bN_2]\{ \hat{u}_1 \} \}, \]
\[ D_{\bu_2}[F]\{ \hat{\bu}_2 \} = \partial_{N_1}[F]\{ D_{\bu_2}[N_1]\{ \hat{\bu}_2 \} \} + \partial_{\bN_2}[F]\{ D_{\bu_2}[\bN_2]\{ \hat{\bu}_2 \} \}. \]

And finally, we expand the directional derivatives of the component of the external operator \(\bN\):

\[ D_{u_1}[N_1]\{ \hat{u}_1 \} = \frac{\partial N_1}{\partial o_1} D_{u_1} [o_1]\{ \hat{u}_1 \} + \frac{\partial N_1}{\partial \bo_2} \cdot \underbrace{D_{u_1} [\bo_2]\{ \hat{u}_1 \}}_{=\bzero}, \]
\[ D_{u_1}[\bN_2]\{ \hat{u}_1 \} = \frac{\partial \bN_2}{\partial o_1} D_{u_1} [o_1]\{ \hat{u}_1 \} + \frac{\partial \bN_2}{\partial \bo_2} \cdot \underbrace{D_{u_1} [\bo_2]\{ \hat{u}_1 \}}_{=\bzero}, \]
\[ D_{\bu_2}[N_1]\{ \hat{\bu}_2 \} = \frac{\partial N_1}{\partial o_1} \underbrace{D_{\bu_2} [o_1]\{ \hat{\bu}_2 \}}_{=0} + \frac{\partial N_1}{\partial \bo_2} \cdot D_{\bu_2} [\bo_2]\{ \hat{\bu}_2 \}, \]
\[ D_{\bu_2}[\bN_2]\{ \hat{\bu}_2 \} = \frac{\partial \bN_2}{\partial o_1} \underbrace{D_{\bu_2} [o_1]\{ \hat{\bu}_2 \}}_{=0} + \frac{\partial \bN_2}{\partial \bo_2} \cdot D_{\bu_2} [\bo_2]\{ \hat{\bu}_2 \}, \]

While all directional derivatives of the operands \(D_{\bu_i} [\bo_j]\{ \hat{\bu}_i \}\) are handled automatically by UFL, the partial derivatives of \(\bN\) with respect to its operands must be explicitly provided by the user. That is why, in practice, we just need to know the partial derivatives of the external operators:

\[ \frac{\partial \bN}{\partial o_1} = \left(\frac{\partial N_1}{\partial o_1}, \frac{\partial \bN_2}{\partial o_1} \right), \]
\[ \frac{\partial \bN}{\partial \bo_2} = \left( \frac{\partial N_1}{\partial \bo_2}, \frac{\partial \bN_2}{\partial \bo_2} \right). \]

As mentioned previously, in the context of mixed elements, we work with block objects, which means that the values of, e.g., \(\frac{\partial N_1}{\partial o_1}\) and \(\frac{\partial \bN_2}{\partial o_1}\) must be stored as a single contiguous flattened array preserving the order of the blocks. See examples in test_mixed_element_space: a-latyshev/dolfinx-external-operator.

After UFL differentiation of the form \(F\), a new mixed element space \(\bQ_2 = \bQ_{12} \times \bQ_{22}\) will be allocated, with the following mathematical shapes:

\[\begin{split} \mathrm{shape}(\bq_{12}) = (2), \quad \bq_{12} \in \bQ_{12},\\ \mathrm{shape}(\bq_{22}) = (2,2), \quad \bq_{22} \in \bQ_{22}.\\ \end{split}\]

Important

Since the operand \(o_1\) is a scalar, differentiation with respect to \(o_1\) does not change the mathematical shape. Therefore, there is no need to allocate a new function space \(\bQ_{1}\), and we can simply reuse \(\bV\) for \(\frac{\partial \bN}{\partial o_1}\). This behavior may change in future releases of dolfinx-external-operator when it becomes necessary to decrease the polynomial degree for the space where the derivative of the external operator lives.