DirichletBC object in dolfinx

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?

1 Like

In the latter approach, there is no connectivity between the full space and the collapsed sub-spaces.
Therefore, you will apply the Dirichlet conditions on the dofs in the collapsed space, which is not the same as those in the full space.
You can easily see this by printing the results of locate_dofs_leftBdry in the two cases.

2 Likes