FEniCS differences between Function, TrialFunction and TestFunction

The FEniCS project allows for simple solution of partial differential equations. However, getting started from examples is so quick, it is easy to miss how the inner-workings of it behave. This should not happen (especially if it is a PhD project). There are three vital pieces of the puzzle that it might not be clear what they are for, and the documentation does not help here: the functions TrialFunction, TestFunction, and Function.

The thing is that, in the usual Finite Element Methods, we only have the distinction between the trial function u \in V_h and test function v \in V, and even then the distinction is often blurry. In fact, technically, the spaces V_h and V can be different. However, most of the time we take them to be the same (for example, the same discrete space of piecewise linear functions). The names we give them is just to have clearer in our heads what role they play in the game, but we could as well say “two functions in V“. Then why would FEniCS have even a three-fold difference? You can quickly check for yourself that, for example, if you swap the TrialFunction for a Function, FEniCS will complain.

There is no documentation on the topic as far as I have found, so these are my (maybe mistaken) deductions.

The meaning of the TrialFunction is to let FEniCS know what function we are solving for. In fact, when we call

solve(A, u_.vector(), b)

FEniCS expects to find a TrialFunction in A, which is supposed to be the function we are looking for. On the other hand, u_ is the symbol in which the result will be stored, and this needs to be a Function (not `Trial`, not `Test`, just a regular `Function`).

What about the TestFunction? FEniCS expects one as well in A, but why would it care? Well, the way we obtain a (finite) linear system to solve when using FEM, is by rewriting the problem in terms of the basis hat functions \phi_i. In fact, when solving the problem

\int u_h' v' dx = \int f v dx

exploiting the fact that v \in V = \{ \text{piece-wise linear functions null at borders} \}, we can rewrite it in terms of the basis of V as

\int u_h' \phi_i' dx = \int f \phi_i dx, \ \ i = 1, \cdots, n-1

and here is where the role of the `TrialFunction` comes in! If FEniCS knows v is a trial function, then it can do this replacement with basis functions and effectively build the linear system.

Technically, TrialFunction, `TestFunction` and simple Function can be distinguished either because they support different methods, as shown in the screenshot below, or by checking the type of a given variable. `TrialFunction` and `TestFunction` are of type dolfin.function.argument.Argument, which is the same as fenics.function.argument.Argument, while Function is of type dolfin.function.function.Function.

fenics trialfunction testfunction funciton

Further technical details: by default, TrialFunction is an Argument with number == 1, while `TestFunction` has `number == 0` (check /dolfin/function/argument.py). Argument numbers can be checked through u.number():

import fenics as fen
mesh = fen.UnitSquareMesh(10,10)
V = fen.VectorFunctionSpace(mesh, 'P', 2)

trial = fen.TrialFunction(V)
test = fen.TestFunction(V)

trial.number() == 1 # True
test.number() == 0  # True


So, in the end:

  • FEniCS expects at least one TrialFunction and at least one TestFunction in each variational problem to be solved.
  • FEniCS expects no more than one TrialFunction per problem (cannot mixed them!).
  • Was this Helpful ?
  • yes   no

One thought on “FEniCS differences between Function, TrialFunction and TestFunction

  1. I came across this article after questioning again everything I learned about Fenics. Very well explained, thanks a lot!

Leave a Reply

Your email address will not be published. Required fields are marked *