Having the displacement constant on the top would correspond to a null gradient condition for the displacement on this region.
To have your Lagrange multiplier living only on the top-boundary, you need to define the corresponding submesh and functionspace. Note that if your constrain is a zero gradient, your Lagrange multiplier (and then the function space it belongs to) will be vectorial.
As you might have seen in the demo, you can define such a submesh by marking the appropriate mesh entities and using MeshView
marker = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0)
class TopBoundary(SubDomain):
def inside(self, x, on_boundary):
return near(x[1], 1) # if top is y = 1 for example
# Marking facets that are on TopBoundary and creating the corresponding submesh
TopBoundary().mark(marker,1)
submesh_top = MeshView.create(marker, 1)
Then you can define the function space for your Lagrange multiplier as
LM = VectorFunctionSpace(submesh_top, ... )
and add this function space in the definition of your MixedFunctionSpace
.
When writing your variational form, you need to define the integration domain, especially for the terms involving the Lagrange multiplier that you will integrate only on the top boundary. It might look like that :
dL = Measure("dx", domain=submesh_top)
a = .... + inner(grad(u),e)*dL
You can also have a look to this post involving Lagrange multiplier(s).