I am currently migrating a significant amount of code to DOLFINx. Meanwhile, I have developed two minimal examples—one for DOLFINx and another for DOLFIN—to compare their performance in solving nonlinear mechanics problems.
Preliminary observations suggest that DOLFINx runs considerably slower than DOLFIN, even though both were installed using Spack.
Using dolfinx
spack:
# add package specs to the `specs` list
specs:
- python
- adios2+python
- fenics-dolfinx+adios2+petsc cflags=-O3 fflags=-O3
- py-fenics-dolfinx cflags=-O3 fflags=-O3
- py-pip
- python +optimizations
view: true
concretizer:
unify: true
packages:
gcc:
externals:
- spec: gcc@13.3.0 languages:='c,c++,fortran'
prefix: /usr
extra_attributes:
compilers:
c: /usr/bin/gcc
cxx: /usr/bin/g++
fortran: /usr/bin/gfortran
from dolfinx import log, default_scalar_type
from dolfinx.fem.petsc import NonlinearProblem
from dolfinx.nls.petsc import NewtonSolver
import numpy as np
import ufl
from mpi4py import MPI
from dolfinx import fem, mesh
########################################################################
## 1. 定义网格与函数空间
########################################################################
L = 20.0
domain = mesh.create_box(MPI.COMM_WORLD, [[0.0, 0.0, 0.0], [L, 1, 1]], [
40, 10, 10], mesh.CellType.tetrahedron)
V = fem.functionspace(domain, ("Lagrange", 1, (domain.geometry.dim, )))
########################################################################
## 2. 定义边界
########################################################################
def left(x):
return np.isclose(x[0], 0)
def right(x):
return np.isclose(x[0], L)
V = fem.functionspace(domain, ("Lagrange", 1, (domain.geometry.dim, )))
fdim = domain.topology.dim - 1
left_facets = mesh.locate_entities_boundary(domain, fdim, left)
right_facets = mesh.locate_entities_boundary(domain, fdim, right)
marked_facets = np.hstack([left_facets, right_facets])
marked_values = np.hstack(
[np.full_like(left_facets, 1), np.full_like(right_facets, 2)])
sorted_facets = np.argsort(marked_facets)
facet_tag = mesh.meshtags(
domain, fdim, marked_facets[sorted_facets], marked_values[sorted_facets])
u_bc = np.array((0,) * domain.geometry.dim, dtype=default_scalar_type)
left_dofs = fem.locate_dofs_topological(V, facet_tag.dim, facet_tag.find(1))
bcs = [fem.dirichletbc(u_bc, left_dofs, V)]
########################################################################
## 3. 定义本构关系
########################################################################
B = fem.Constant(domain, default_scalar_type((0, 0, 0)))
T = fem.Constant(domain, default_scalar_type((0, 0, 0)))
v = ufl.TestFunction(V)
disp = fem.Function(V)
d = len(disp)
I = ufl.variable(ufl.Identity(d))
F = ufl.variable(I + ufl.grad(disp))
C = ufl.variable(F.T * F)
Ic = ufl.variable(ufl.tr(C))
J = ufl.variable(ufl.det(F))
E = default_scalar_type(1.0e4)
nu = default_scalar_type(0.3)
mu = fem.Constant(domain, E / (2 * (1 + nu)))
lmbda = fem.Constant(domain, E * nu / ((1 + nu) * (1 - 2 * nu)))
psi = (mu / 2) * (Ic - 3) - mu * ufl.ln(J) + (lmbda / 2) * (ufl.ln(J))**2
P = ufl.diff(psi, F)
########################################################################
## 4. 定义弱形式
########################################################################
metadata = {"quadrature_degree": 4}
ds = ufl.Measure('ds', domain=domain,
subdomain_data=facet_tag, metadata=metadata)
dx = ufl.Measure("dx", domain=domain, metadata=metadata)
F = ufl.inner(ufl.grad(v), P) * dx - ufl.inner(v, B) * \
dx - ufl.inner(v, T) * ds(2)
########################################################################
## 5. 定义非线性求解器
########################################################################
problem = NonlinearProblem(F, disp, bcs)
solver = NewtonSolver(domain.comm, problem)
solver.atol = 1e-7
solver.rtol = 1e-6
solver.convergence_criterion = "incremental"
########################################################################
## 6. 求解
########################################################################
tval0 = -1.5
from dolfinx.geometry import bb_tree, compute_colliding_cells, compute_collisions_points
tree = bb_tree(domain, domain.geometry.dim)
x0 = np.array([L/2, 0.5, 0.5], dtype=default_scalar_type)
cell_candidates = compute_collisions_points(tree, x0)
cell = compute_colliding_cells(domain, cell_candidates, x0).array
first_cell = cell[0]
log.set_log_level(log.LogLevel.INFO)
for n in range(1, 3):
T.value[2] = n * tval0
num_its, converged = solver.solve(disp)
assert (converged)
disp.x.scatter_forward()
print(disp.eval(x0, first_cell)[:3])
time python3 quick-start.py
[2025-06-13 15:58:21.265] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:22.893] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:24.225] [info] Newton iteration 2: r (abs) = 12.565869115552855 (tol = 1e-07), r (rel) = 0.1002671312122483 (tol = 1e-06)
[2025-06-13 15:58:24.387] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:25.693] [info] Newton iteration 3: r (abs) = 0.8785434206693661 (tol = 1e-07), r (rel) = 0.00701018191625794 (tol = 1e-06)
[2025-06-13 15:58:25.854] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:27.160] [info] Newton iteration 4: r (abs) = 0.39482612960830427 (tol = 1e-07), r (rel) = 0.0031504453038159992 (tol = 1e-06)
[2025-06-13 15:58:27.322] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:28.645] [info] Newton iteration 5: r (abs) = 0.0036403735824912563 (tol = 1e-07), r (rel) = 2.904771745596795e-05 (tol = 1e-06)
[2025-06-13 15:58:28.807] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:30.146] [info] Newton iteration 6: r (abs) = 1.783858658903483e-05 (tol = 1e-07), r (rel) = 1.4233984818049848e-07 (tol = 1e-06)
[2025-06-13 15:58:30.146] [info] Newton solver finished in 6 iterations and 6 linear solver iterations.
[-0.07666793 0.01112278 -1.0976045 ]
[2025-06-13 15:58:30.325] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:31.831] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:33.183] [info] Newton iteration 2: r (abs) = 10.852971025363265 (tol = 1e-07), r (rel) = 0.09295613408995217 (tol = 1e-06)
[2025-06-13 15:58:33.344] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:34.667] [info] Newton iteration 3: r (abs) = 1.6749227835683338 (tol = 1e-07), r (rel) = 0.014345781122591971 (tol = 1e-06)
[2025-06-13 15:58:34.827] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:36.178] [info] Newton iteration 4: r (abs) = 8.261046727151854 (tol = 1e-07), r (rel) = 0.07075619804916829 (tol = 1e-06)
[2025-06-13 15:58:36.340] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:37.664] [info] Newton iteration 5: r (abs) = 0.34888363707070985 (tol = 1e-07), r (rel) = 0.002988202407759547 (tol = 1e-06)
[2025-06-13 15:58:37.825] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:39.147] [info] Newton iteration 6: r (abs) = 0.2895785528927952 (tol = 1e-07), r (rel) = 0.002480251972420242 (tol = 1e-06)
[2025-06-13 15:58:39.308] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:40.632] [info] Newton iteration 7: r (abs) = 0.0004160114978664066 (tol = 1e-07), r (rel) = 3.5631552400037086e-06 (tol = 1e-06)
[2025-06-13 15:58:40.792] [info] PETSc Krylov solver starting to solve system.
[2025-06-13 15:58:42.115] [info] Newton iteration 8: r (abs) = 3.864113793945916e-07 (tol = 1e-07), r (rel) = 3.3096290327269865e-09 (tol = 1e-06)
[2025-06-13 15:58:42.115] [info] Newton solver finished in 8 iterations and 8 linear solver iterations.
[-0.27184167 0.02014685 -2.05597763]
real 0m21.484s
user 0m24.166s
sys 0m0.655s
Using dolfin
spack:
specs:
- kokkos-kernels@4.3.00 +cuda cuda_arch=89 %gcc@11.4.0
- kokkos@4.3.00 ~openmp +cuda +cuda_lambda +cuda_constexpr +wrapper cuda_arch=89
cxxstd=20
# FEniCS
- fenics@2019.1.0.post0 +zlib build_type=Release cflags="-O3"
- petsc@3.14.0 +mumps +hdf5
- boost@1.71.0
- openmpi@4.0.6 +cuda
- python@3.10.10 +optimizations
- py-matplotlib
- py-cython@0.29.36
# NPUHeart
- muparser # 2.3.4
- fmt@10.1.1
- nlohmann-json@3.11.2
- py-pip
- spdlog
- pugixml
view: true
concretizer:
unify: true
packages:
all:
compiler: [gcc@11.4.0]
from fenics import *
########################################################################
## 1. 定义网格与函数空间
########################################################################
L = 20.0
domain = BoxMesh(Point(0.0, 0.0, 0.0), Point(L, 1.0, 1.0), 40, 10, 10)
V = VectorFunctionSpace(domain, "Lagrange", 1)
# ########################################################################
# ## 2. 定义边界
# ########################################################################
class Left(SubDomain):
def inside(self, x, on_boundary):
return x[0] < DOLFIN_EPS and on_boundary
class Right(SubDomain):
def inside(self, x, on_boundary):
return near(x[0], L) and on_boundary
boundaries = MeshFunction("size_t", domain, domain.topology().dim()-1)
boundaries.set_all(0)
Left().mark(boundaries, 1)
Right().mark(boundaries, 2)
noslip = Constant((0.0, 0.0, 0.0))
bc0 = DirichletBC(V, noslip, boundaries, 1)
bcs = [bc0]
########################################################################
## 3. 定义本构关系
########################################################################
v = TestFunction(V)
u = TrialFunction(V)
disp = Function(V, name="displacement")
F = variable(grad(disp) + Identity(len(disp)))
C = F.T * F
Ic = tr(C)
J = det(F)
E = 1.0e4
nu = 0.3
mu = Constant(E / (2 * (1 + nu)))
lmbda = Constant(E * nu / ((1 + nu) * (1 - 2 * nu)))
psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lmbda / 2) * (ln(J))**2
P = diff(psi, F)
########################################################################
## 4. 定义弱形式
########################################################################
ds = Measure('ds', domain=domain, subdomain_data=boundaries)
T = Expression(("0.0", "0.0", "data"), degree=1, domain=domain, data = 0.0)
H = inner(P, grad(v))*dx(degree=5) - inner(v, T)*ds(subdomain_id=2, degree=5)
J = derivative(H, disp, u)
########################################################################
## 5. 定义非线性求解器
########################################################################
solver_parameters={
"newton_solver": {
"linear_solver": "lu",
"absolute_tolerance": 1.0e-7,
"relative_tolerance": 1e-6
}
}
########################################################################
## 6. 求解
########################################################################
tval0 = -1.5
for n in range(1, 3):
T.data = n * tval0
solve(H == 0, disp, J=J, bcs=bcs, solver_parameters=solver_parameters)
print(disp(L/2, 0.5, 0.5))
time python3 quick_start.py
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 1.425e-01 (tol = 1.000e-07) r (rel) = 1.000e+00 (tol = 1.000e-06)
Newton iteration 1: r (abs) = 6.930e+02 (tol = 1.000e-07) r (rel) = 4.863e+03 (tol = 1.000e-06)
Newton iteration 2: r (abs) = 2.177e+01 (tol = 1.000e-07) r (rel) = 1.528e+02 (tol = 1.000e-06)
Newton iteration 3: r (abs) = 4.303e-02 (tol = 1.000e-07) r (rel) = 3.019e-01 (tol = 1.000e-06)
Newton iteration 4: r (abs) = 2.350e-02 (tol = 1.000e-07) r (rel) = 1.649e-01 (tol = 1.000e-06)
Newton iteration 5: r (abs) = 8.959e-07 (tol = 1.000e-07) r (rel) = 6.286e-06 (tol = 1.000e-06)
Newton iteration 6: r (abs) = 9.850e-11 (tol = 1.000e-07) r (rel) = 6.911e-10 (tol = 1.000e-06)
Newton solver finished in 6 iterations and 6 linear solver iterations.
[-0.07666793 0.01112278 -1.0976045 ]
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 1.425e-01 (tol = 1.000e-07) r (rel) = 1.000e+00 (tol = 1.000e-06)
Newton iteration 1: r (abs) = 6.010e+02 (tol = 1.000e-07) r (rel) = 4.217e+03 (tol = 1.000e-06)
Newton iteration 2: r (abs) = 1.618e+01 (tol = 1.000e-07) r (rel) = 1.135e+02 (tol = 1.000e-06)
Newton iteration 3: r (abs) = 4.238e-01 (tol = 1.000e-07) r (rel) = 2.974e+00 (tol = 1.000e-06)
Newton iteration 4: r (abs) = 4.155e+00 (tol = 1.000e-07) r (rel) = 2.915e+01 (tol = 1.000e-06)
Newton iteration 5: r (abs) = 7.550e-03 (tol = 1.000e-07) r (rel) = 5.298e-02 (tol = 1.000e-06)
Newton iteration 6: r (abs) = 4.902e-03 (tol = 1.000e-07) r (rel) = 3.440e-02 (tol = 1.000e-06)
Newton iteration 7: r (abs) = 9.470e-09 (tol = 1.000e-07) r (rel) = 6.644e-08 (tol = 1.000e-06)
Newton solver finished in 7 iterations and 7 linear solver iterations.
[-0.27184167 0.02014685 -2.05597763]
real 0m4.896s
user 0m3.837s
sys 0m1.053s