Form compilation is much slower when running the script for the first time

Here is a simple code snippet for reproduction:

from dolfinx import fem, mesh, common, default_scalar_type
import basix.ufl
import ufl
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD

Nx = 100; Ny = 100
msh = mesh.create_rectangle(comm, [np.array([0, 0]), np.array([Nx, Ny])], [Nx, Ny], cell_type=mesh.CellType.triangle, dtype=default_scalar_type)

V = fem.functionspace(msh, basix.ufl.element('CG', msh.basix_cell(), degree=2))
u = ufl.TestFunction(V); v = ufl.TrialFunction(V)
F = ufl.inner(ufl.grad(u), ufl.grad(v))*ufl.dx
lhs, rhs = ufl.lhs(F), ufl.rhs(F)

with common.Timer('Compiling form'):
    a, L = fem.form(lhs), fem.form(rhs)

common.list_timings(comm, [common.TimingType.wall])

When I run the script for the first time, the time cost is:

Compiling form                                                              |     1  0.320000  0.320000

After the first run, the time cost of subsequent running is negligible:

Compiling form                                                              |     1  0.000000  0.000000

And if I change the size of the mesh or if I change the type of cell to quadrilateral, the time cost is still negligible. But if I run the code after a while (this seems to be irregular), the time cost will be large again.

The time difference is more significant in my real application. So I wonder if this is normal and what is the reason for this difference. The dolfinx version I use is 0.9.0 (conda).

This is normal. If the form has not changed, the form does not need to be compiled again, as the compiled form is cached by dolfinx. If you change the expression of the form in your MWE you will see that it gets recompiled.

3 Likes

A general rule of thumb is that one should only call fem.form once within a script (especially not within loops, as this will do all the magic of generating C code, as described in: Generating code for assembling tensors β€” FEniCS Workshop).

This would only happen if one can’t find the form within the cache. As mentioned above, try refactoring your code such that dolfinx.fem.form is only called once.

If you have a use-case where you believe you have to call it multiple times, please make an illustrative example that we could have a look at. Guidelines for setting up forms can be found at: Efficient usage of the Unified Form Language β€” FEniCS Workshop

2 Likes

Thank you for your explanation! I will change my code and perform form compilation only once in my code. I have another question. In my application, the input parameters will change frequently but the variational form will not. I wonder where to find the cached C code and how to make sure it is properly saved and can be used directly whenever I perform the script?

As shown in:

If the input values are constants, then wrapping them as dolfinx.fem.Constant will ensure that the form compiled is the same irregardless of the input value.

If it is not constant, is it an expression with ufl.SpatialCoordinate?

Thank you, wrapping the input values in dofinx.fem.Constant works.