Hi,
I am trying to understand the DirichetBC
object along with the locate_dofs_geometrical
function in dolfinx
(version: 2019.2.9.99
). Consider a simple 2D elasticity problem
\int_\Omega \sigma(u):\varepsilon(\delta u)\ dx = \int_\Omega f:\delta u\ dx\quad \forall \delta u \in \mathcal{U}_0
and
u_1 = 0 on x_1=0
u_2 = 0 on x_2= 0
translated into the following MWE:
from dolfinx import Function, FunctionSpace, VectorFunctionSpace, UnitSquareMesh, solve, plotting, DirichletBC, Constant
from dolfinx.fem import locate_dofs_topological, locate_dofs_geometrical, apply_lifting, set_bc, assemble_matrix, assemble_vector
from dolfinx.mesh import locate_entities_geometrical
from dolfinx.io import XDMFFile
from dolfinx.specialfunctions import SpatialCoordinate
from dolfinx.cpp.mesh import CellType
from ufl import ds, dx, grad, inner, dot, Identity, TestFunction, TrialFunction, sym, tr
import numpy as np
from mpi4py import MPI
from petsc4py import PETSc
msh = UnitSquareMesh(MPI.COMM_WORLD, 10, 10)
V = VectorFunctionSpace(msh, ("CG", 1))
u_, du = TrialFunction(V), TestFunction(V)
eps = lambda v: sym(grad(v))
mu, lmbda = Constant(msh, 1.), Constant(msh, 5)
sigma = lambda v: 2*mu*eps(v) + lmbda * tr(eps(v))*Identity(len(v))
a = inner(sigma(u_), eps(du))*dx
L = inner(Constant(msh, (1., 0)), du)*dx
locate_dofs_leftBdry = locate_dofs_geometrical((V.sub(0), V.sub(0).collapse()), lambda x: np.isclose(x[0], 0.))
locate_dofs_botBdry = locate_dofs_geometrical((V.sub(1), V.sub(1).collapse()), lambda x: np.isclose(x[1], 0.))
ubcLeft= Function(V.sub(0).collapse())
with ubcLeft.vector.localForm() as uloc:
uloc.set(0.)
ubcBottom = Function(V.sub(1).collapse())
with ubcBottom.vector.localForm() as uloc:
uloc.set(0.)
bcs = [DirichletBC(ubcLeft, locate_dofs_leftBdry, V.sub(0)),
DirichletBC(ubcBottom, locate_dofs_botBdry, V.sub(1))] # this isn't completely obvious to me
A, b = assemble_matrix(a, bcs), assemble_vector(L)
A.assemble()
apply_lifting(b, [a], [bcs])
b.ghostUpdate(addv=PETSc.InsertMode.ADD,
mode=PETSc.ScatterMode.REVERSE)
set_bc(b, bcs)
solver = PETSc.KSP().create(MPI.COMM_WORLD)
solver.setType(PETSc.KSP.Type.PREONLY)
solver.getPC().setType(PETSc.PC.Type.LU)
solver.setOperators(A)
uh = Function(V)
uh.name="u"
# uh.set(0.)
solver.solve(b, uh.vector)
Alternatively:
If I search for the boundary dofs using
locate_dofs_leftBdry = locate_dofs_geometrical(V.sub(0).collapse(), lambda x: np.isclose(x[0], 0.))
locate_dofs_botBdry = locate_dofs_geometrical(V.sub(1).collapse(), lambda x: np.isclose(x[1], 0.))
and then create the DirichletBC
object as previously done
with ubcLeft.vector.localForm() as uloc:
uloc.set(0.)
with ubcBottom.vector.localForm() as uloc:
uloc.set(0.)
bcs = [DirichletBC(ubcLeft, locate_dofs_leftBdry),
DirichletBC(ubcBottom, locate_dofs_botBdry)]
the boundary conditions aren’t enforced properly.
Can anyone point to the problems with the latter aproach?