Hello Everyone,
I am trying to understand the mixed function spaces implementation in the context of stokes problem. I am using Taylor-Hood elements. I have followed the Mixed formulation for the Poisson equation demo from the fenicsx documentation for setting up spaces, bcs etc. However, I am getting inf solution for velocity and pressure everywhere. It should atleast be equal to the applied boundary condition values at the Dirichlet dofs. I checked my identified degrees of freedom for velocity and pressure, which seems correct. Can someone point out what I might be missing?
from dolfinx import fem, mesh, io, geometry
import numpy as np
import ufl
from mpi4py import MPI
from basix.ufl import element, mixed_element
from petsc4py import PETSc
from dolfinx.fem.petsc import LinearProblem
# Create mesh
domain = mesh.create_unit_square(MPI.COMM_WORLD, 1, 1)
# Taylor-Hood elements (P2-P1)
P2 = element("Lagrange", domain.basix_cell(), 2, shape=(2,)) # Vector element for velocity
P1 = element("Lagrange", domain.basix_cell(), 1) # Scalar element for pressure
TH = mixed_element([P2, P1])
W = fem.functionspace(domain, TH)
# Get subspace of V
V0 = W.sub(0)
Q0 = W.sub(1)
V, V_to_W = W.sub(0).collapse()
Q, Q_to_W = W.sub(1).collapse()
# Define trial and test functions
(u, p) = ufl.TrialFunctions(W)
(v, q) = ufl.TestFunctions(W) # Test functions
# Define manufactured solution
x = ufl.SpatialCoordinate(domain)
u_exact = ufl.as_vector([
ufl.sin(2 * np.pi * x[0]) * ufl.cos(2 * np.pi * x[1]),
-ufl.cos(2 * np.pi * x[0]) * ufl.sin(2 * np.pi * x[1])])
p_exact = ufl.sin(2 * np.pi * x[0]) * ufl.sin(2 * np.pi * x[1])
# Create a Function to hold the exact solution
u_exact_func = fem.Function(V)
u_exact_func.interpolate(lambda x: np.array([
np.sin(2 * np.pi * x[0]) * np.cos(2 * np.pi * x[1]),
-np.cos(2 * np.pi * x[0]) * np.sin(2 * np.pi * x[1])
], dtype=np.float64))
# Apply boundary conditions
facets = mesh.locate_entities_boundary(domain, 1, lambda x: np.full(x.shape[1], True))
dofs_V = fem.locate_dofs_topological((V0, V), 1, facets)
print("velocity essential dofs", dofs_V)
bc = fem.dirichletbc(u_exact_func, dofs_V, V0)
# Fix pressure at one point to remove null space
# Find a point (e.g., first vertex)
def is_corner(x, tol=1e-5):
return np.logical_and(np.isclose(x[0], 0.0, atol=tol),
np.isclose(x[1], 0.0, atol=tol))
corner = mesh.locate_entities_boundary(domain, 0, is_corner)
pressure_dof = fem.locate_dofs_topological((Q0, Q), 0, corner)
print("pressure essential dofs", pressure_dof)
# Create pressure constraint
zero = fem.Function(Q)
zero.interpolate(lambda x: np.array([0.0], dtype=np.float64))
bc_p = fem.dirichletbc(zero, pressure_dof, Q0)
# Combine BCs
bcs = [bc, bc_p]
# Compute f = -νΔu + ∇p
ν = 1.0
f = -ν * ufl.div(ufl.grad(u_exact)) + ufl.grad(p_exact)
a = ν * ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx - p * ufl.div(v) * ufl.dx - q * ufl.div(u) * ufl.dx
L = ufl.inner(f, v) * ufl.dx
# Solve
wh = fem.Function(W)
problem = fem.petsc.LinearProblem(a, L, bcs= bcs,
petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
wh = problem.solve()
uh, ph = wh.sub(0), wh.sub(1) # Split solution
print(uh.x.array)
print(ph.x.array)
## Verify solution
print("Velocity min/max:", np.min(uh.x.array), np.max(uh.x.array))
print("Pressure min/max:", np.min(ph.x.array), np.max(ph.x.array))
# Compute errors
error_u = fem.assemble_scalar(fem.form(ufl.inner(uh - u_exact, uh - u_exact) * ufl.dx)) ** 0.5
error_p = fem.assemble_scalar(fem.form((ph - p_exact)**2 * ufl.dx)) ** 0.5
print(f"Taylor-Hood errors: u_L2 = {error_u:.2e}, p_L2 = {error_p:.2e}")
The output looks like this.
velocity dofs [array([ 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 15, 16, 17, 18, 19, 20],
dtype=int32), array([ 6, 7, 0, 1, 8, 9, 2, 3, 4, 5, 12, 13, 14, 15, 16, 17],
dtype=int32)]
pressure dofs [array([12], dtype=int32), array([0], dtype=int32)]
[inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf
inf inf inf inf]
[inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf inf
inf inf inf inf]
Velocity min/max: inf inf
Pressure min/max: inf inf
Taylor-Hood errors: u_L2 = nan, p_L2 = inf