Implement linear combination assignment - #62
Open
jorgensd wants to merge 13 commits into
Open
Conversation
finsberg
requested changes
Aug 19, 2026
finsberg
left a comment
Member
There was a problem hiding this comment.
Very nice feature! Added a few comments.
Should probably also add some tests that checks error handling when functions for different function spaces are used and in general a bit more exhausting unit testing of the utility functions in utils.py
Co-authored-by: Henrik Finsberg <henrikfinsberg@hotmail.com>
… other function, equivalent of assigning a constant)
finsberg
requested changes
Aug 20, 2026
Use new dagtraverser to extract linear combination. Create new floatifier traverser to convert the UFL expression for the weight to a float.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implementation of Linear Combination Assignments in FEniCSx
This document outlines the practical usage and mathematical foundation for evaluating linear combinations of finite element functions, parsing their components, and deriving their corresponding adjoints within the
dolfinx-adjointframework.Practical Usage in
dolfinx-adjointIn$L^2$ -projection or spatial interpolation, the framework intercepts the assignment. By recognizing that the operation is purely linear and operates within the same function space, it translates the continuous UFL expression into direct, highly efficient vector operations on the underlying degrees of freedom (DOFs).
dolfinx-adjoint, this mathematical optimization is exposed through theassign(linear_expression, z)function. Instead of treating a linear combination as a generic UFL expression that requires a costlyParsing the Linear Expression
Before the assignment can be executed on the DOF arrays, the continuous UFL expression must be decomposed. The framework recursively traverses the UFL abstract syntax tree (using
extract_linear_combination) to break the expression down into a standard sum of weighted functions:During this traversal, the algorithm enforces a strict separation for each term:
Constant, aRealspace function (a globally uniform constant stored as a finite element function), or a complex product and division of multiple scalar values.Once parsed, the expression is reduced to a list of
(weight, function)pairs, which can then be directly applied to the arrays.The Forward Pass: Interpolation as an$\mathbb{R}^N$ Identity
In the finite element method, a function$u$ belonging to a function space $V$ is represented as a linear combination of basis functions $\phi_i(x)$ :
where$u_i$ are the discrete degrees of freedom. The interpolation operator $\Pi$ maps a continuous function $f(x)$ into $V$ using the dual basis of nodal functionals $l_i$ :
By definition, the basis functions and nodal functionals satisfy the biorthogonality property:
When$f(x)$ is strictly a linear combination of other finite element functions defined on the exact same function space $V$ (as guaranteed by the parsing step), it can be written as:
Applying the nodal functional$l_i$ to this $f(x)$ yields:
Because$l_i(f) = f_i$ , the continuous interpolation operator reduces directly to an identity mapping in $\mathbb{R}^N$ . This mathematically proves that assigning a linear combination of functions from the same space does not require solving a projection system; it is perfectly exact to apply the weights $c_k$ and functions $v_k$ directly to the underlying DOF arrays.
The Adjoint Pass: Deriving Sensitivities
In the algorithmic differentiation tape, let$J$ be the objective functional. For a forward assignment $u = \text{expr}(v, r)$ where $v$ is a spatial function and $r$ is a global constant weight, we receive the incoming adjoint sensitivities $\bar{u}_i = \frac{\partial J}{\partial u_i}$ .
Adjoint of a Spatial Function Term ($v$ )
Because the assignment maps DOFs pointwise (i.e.,$u_i$ depends only on $v_i$ ), the chain rule for the derivative with respect to the spatial function $v$ is strictly local to each DOF:
In the UFL-based implementation, this is evaluated by taking the symbolic derivative of the expression with respect to$v$ , in the direction of the adjoint vector $\bar{u}$ . Because the underlying operation is a linear combination, applying the directional derivative automatically multiplies the local coefficient by the incoming adjoint sensitivity.
Adjoint of a Constant Term ($r$ )
When assigning a constant$r$ (such as a function in the $u$ , the scalar $r$ is broadcasted to all $N$ degrees of freedom in the mesh. Consequently, a change in $r$ affects every $u_i$ . The chain rule dictates that the adjoint derivative must sum the contributions from all DOFs:
Realspace) to a spatial functionTo implement this, the code performs the following steps:
Realspace).This inner product exactly executes the required summation over$i$ , collapsing the $N$ -dimensional spatial sensitivities down to a single global scalar adjoint $\bar{r}$ .