You can also slightly modify a varitional form (if containing vector components) such that it extends in 3D, i.e.
# Solve Stokes eq in XY-plane of a 3D mesh
# Author: Jørgen S. Dokken
# SPDX-License-Identifier: MIT
from mpi4py import MPI
import dolfinx.fem.petsc
import dolfinx
import basix.ufl
import ufl
import numpy as np
nu_val = 1
# Create mesh and mixed function space
mesh = dolfinx.mesh.create_unit_cube(
MPI.COMM_WORLD, 12, 10, 1)
el_u = basix.ufl.element(
"Lagrange", mesh.basix_cell(), 2, shape=(2,)
)
el_p = basix.ufl.element(
"Lagrange",
mesh.basix_cell(),
1,
)
el_w = basix.ufl.mixed_element([el_u, el_p])
W = dolfinx.fem.functionspace(mesh, el_w)
v, q = ufl.TestFunctions(W)
# Define solution vector and/or trial function
w = dolfinx.fem.Function(W)
u, p = ufl.TrialFunctions(W)
# Define integration measures
dx = ufl.Measure("dx", domain=mesh)
ds = ufl.Measure("ds", domain=mesh)
uhat = ufl.as_vector([u[0], u[1], 0])
vhat = ufl.as_vector([v[0], v[1], 0])
# Add artificial forcing in y direction to illustrate the effect of solving in 2D
dst = dolfinx.default_scalar_type
x = ufl.SpatialCoordinate(mesh)
nu = dolfinx.fem.Constant(mesh, dst(nu_val))
f = ufl.as_vector((0,10*x[1],0))
g = dolfinx.fem.Constant(mesh, dst(0))
# Convenience functions for the variational form
def a(u, v):
return nu * ufl.inner(ufl.grad(u), ufl.grad(v)) * dx
def b(p, v):
return -p * ufl.div(v) * dx
def L(v, q):
return ufl.inner(f, v) * dx - ufl.inner(g, q) * dx
# Define stabilized variational form
F = a(uhat, vhat) - b(p, vhat) - b(q, uhat) - L(vhat, q)
mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim)
left_facets = dolfinx.mesh.locate_entities_boundary(mesh, mesh.topology.dim - 1, lambda x: np.isclose(x[0], 0))
V, _ = W.sub(0).collapse()
left_dofs = dolfinx.fem.locate_dofs_topological((W.sub(0),V), mesh.topology.dim-1, left_facets)
u_bc = dolfinx.fem.Function(V)
u_bc.interpolate(lambda x: (x[1]*(1-x[1]), np.zeros_like(x[0])))
bc_u = dolfinx.fem.dirichletbc(u_bc, left_dofs, W.sub(0))
walls = dolfinx.mesh.locate_entities_boundary(mesh, mesh.topology.dim - 1, lambda x: np.isclose(x[1], 0)|np.isclose(x[1], 1))
wall_dofs = dolfinx.fem.locate_dofs_topological((W.sub(0),V), mesh.topology.dim-1, walls)
u_wall = dolfinx.fem.Function(V)
u_wall.interpolate(lambda x: (np.zeros_like(x[0]), np.zeros_like(x[0])))
bc_wall = dolfinx.fem.dirichletbc(u_wall, wall_dofs, W.sub(0))
bcs = [bc_u, bc_wall]
problem = dolfinx.fem.petsc.LinearProblem(ufl.lhs(F), ufl.rhs(F), bcs=bcs, petsc_options={"ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"})
wh = problem.solve()
uh = wh.sub(0).collapse()
converged = problem.solver.getConvergedReason()
print(converged)
assert converged > 0
with dolfinx.io.VTXWriter(mesh.comm, "stokes.bp", [uh], engine="BP5") as writer:
writer.write(0.0)
where I have defined
uhat = ufl.as_vector([u[0], u[1], 0])
vhat = ufl.as_vector([v[0], v[1], 0])
which on a standard 2D grid would be
uhat = u
vhat = v
yielding the following with some artificial forcing in the y direction:
You could of course follow @Jesus_Vellojin proposal if you do not need the 3D geometry at a later stage with the extended field.