Contact boundary condition

Hello Everyone,
I am trying to conduct three point bending test. i want to apply contact boundary condition like the figure show. how to perform it in FEniCS?


I am trying to apply a point boundary condition. But the result is not right. I think that the boundary conditions are different from the experimental ones. Here is my attempt

from dolfin import *
import numpy as np
import matplotlib.pyplot as plt
#creat mesh
##---------L=4W------------------------
wt=10.01
lt=4.0*wt
wn=0.35
an=4.9
mesh = Mesh()
editor = MeshEditor()
editor.open(mesh,'triangle', 2, 2)
editor.init_vertices(16)
editor.init_cells(16)
editor.add_vertex(0, Point(0.0, 0.0))
editor.add_vertex(1, Point(wt, 0.0))
editor.add_vertex(2, Point(2.0*wt-wn/2.0, 0.0))
editor.add_vertex(3, Point(2.0*wt, an))
editor.add_vertex(4, Point(2.0*wt+wn/2.0, 0.0))
editor.add_vertex(5, Point(3.0*wt, 0.0))
editor.add_vertex(6, Point(4.0*wt, 0.0))

editor.add_vertex(7, Point(0.0, an))
editor.add_vertex(8, Point(wt, an))
editor.add_vertex(9, Point(3.0*wt, an))
editor.add_vertex(10, Point(4.0*wt, an))

editor.add_vertex(11, Point(0.0, wt))
editor.add_vertex(12, Point(wt, wt))
editor.add_vertex(13, Point(2.0*wt,wt))
editor.add_vertex(14, Point(3.0*wt, wt))
editor.add_vertex(15, Point(4.0*wt, wt))

editor.add_cell(0, [0, 1, 7])
editor.add_cell(1, [1, 8, 7])
editor.add_cell(2, [1, 2, 8])
editor.add_cell(3, [2, 3, 8])
editor.add_cell(4, [4, 5, 3])
editor.add_cell(5, [5, 9, 3])
editor.add_cell(6, [5, 6, 9])
editor.add_cell(7, [6, 10, 9])
editor.add_cell(8, [7, 8, 11])
editor.add_cell(9, [8, 12, 11])
editor.add_cell(10, [8, 3, 12])
editor.add_cell(11, [3, 13, 12])
editor.add_cell(12, [3, 9, 13])
editor.add_cell(13, [9, 14, 13])
editor.add_cell(14, [9, 10, 14])
editor.add_cell(15, [10, 15, 14])
editor.close()
mesh=refine(mesh)
##---------mesh end -------------------
#--------------------------------------
# change num_refine for mesh refinement
#--------------------------------------
def refine_elemnt(mesh):
    makers = MeshFunction("bool", mesh, mesh.topology().dim())
    makers.set_all(False)
    for cell in cells(mesh):
        if abs(cell.midpoint().x()-23.0)<3.0:
            makers[cell.index()] = True
    mesh=refine(mesh,makers)
    return mesh
num_refine = 5
for i in range(num_refine):
    mesh=refine(mesh)
for i in range(0):
    mesh=refine_elemnt(mesh)
#Import mesh file
#mesh = Mesh('mesh.xml')
#mesh = RectangleMesh(Point(0.0, 0.0), Point(46.0, 10.01), 400, 80)
## Output: the infomation of mesh
print(mesh.hmax())
print(mesh.hmin())
print(mesh.num_cells())
print(mesh.num_vertices())
print(mesh)
file_mesh = File("meshwang.pvd")       
file_mesh << mesh

# Define function space 

W = VectorFunctionSpace(mesh, 'CG', 1)
u, v = TrialFunction(W), TestFunction(W)

# Introduce manually the material parameters
E0 =3.04e3             #N/mm/mm test:3.04e3    
nu=0.36                 #  test:0.36   
mu = E0/(2*(1.0+nu))     #N/mm/mm  test: E0/(2*(1.0+nu))      hirshikesh: 8.0e3 
lmbda = E0*nu/((1.0+nu)*(1.0-2.0*nu))       #N/mm/mm test:E0*nu/((1.0+nu)*(1.0-2.0*nu))  hirshikesh:12.0e3

# Constituive functions
def epsilon(u):
    return sym(grad(u))
def sigma(u):
    return 2.0*mu*epsilon(u)+lmbda*tr(epsilon(u))*Identity(len(u))

# Boundary conditions
#bot = CompiledSubDomain("near(x[1], 0.0) && on_boundary")
def top(x, on_boundary):
    tol = DOLFIN_EPS
    return (abs(x[1] - wt) < tol) and on_boundary
def pointl(x, on_boundary):
    tol = DOLFIN_EPS
    return (abs(x[0] - 0.0) < tol) and (abs(x[1] -0.0) < tol)
def pointr(x, on_boundary):
    tol = DOLFIN_EPS
    return (abs(x[0] - 4.0*wt) < tol) and (abs(x[1] -0.0) < tol)
def pointm(x, on_boundary):
    tol = DOLFIN_EPS
    return (abs(x[0] - 2.0*wt) <= tol) and (abs(x[1] -10.01) <= tol)
load = Expression("t", t = 0.0, degree=1)
bc_ptl = DirichletBC(W, Constant((0.0,0.0)), pointl,method="pointwise")
bc_ptr = DirichletBC(W.sub(1), Constant(0.0), pointr,method="pointwise")
bc_ptm = DirichletBC(W.sub(1), load, pointm,method="pointwise")
bc_u = [bc_ptl, bc_ptr,bc_ptm ]

boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundaries.set_all(0)
AutoSubDomain(top).mark(boundaries,1)
ds = Measure("ds")(subdomain_data=boundaries)
n = FacetNormal(mesh)
#plot(mesh)
# Apply a point load equal to 100 N downward in Y direction at coordinate (23.0,10.01):
class Load(UserExpression):

    def __init__(self, **kwargs):
        super().__init__(degree=kwargs["degree"])

        self.point = kwargs['point']
        self.value = kwargs['value']

    def eval(self, value, x):

        if near(x[0], self.point[0]) and near(x[1], self.point[1]):
            value[0] = self.value[0]
            value[1] = self.value[1]
        else:  
            value[0] = 0
            value[1] = 0

    def value_shape(self):
        return (2,)
Tra = Load(point=(20.02, 10.02), value=(0.0, -100.0), degree=1)
# Variational form
a = inner(sigma(u), grad(v))*dx
f = Constant((0.0, 0.0))
L =  dot(f, v)*ds(1)     

t = 0
deltaT=0.01                   # load up
load_dis =[]                   # load displacement
load_force =[]                 # load force
forcex = []
forcey = []
x_dofs = W.sub(0).dofmap().dofs()
y_dofs = W.sub(1).dofmap().dofs()
# Staggered scheme
while t<0.35:    # real 0.007  test 0.38 mm
    # Compute solution
    u = Function(W)
    solve(a == L, u, bc_u)

    f_ext_unknown = assemble(inner(sigma(u), grad(v))*dx)
    bc_ptm.apply(f_ext_unknown)    
    Fy = 0
    for i in y_dofs:
        Fy += f_ext_unknown[i]
    forcey.append(-Fy)
    load_dis.append(t)
    t += deltaT
    load.t=t
x1 = [0.0,0.03081,0.07841,0.11827,0.16532,0.20054,0.25952,0.27453,0.30665,0.34078,0.35061]
y1 = [0.0,8.53131,21.25996,32.32954,44.35104,53.43517,69.61796,73.61607,80.71474,89.06452,90.69639]
plt.figure(1)
plt.plot(load_dis, forcey,'b-',label='simulation load'.format(0))
plt.plot(x1, y1,'o',label='test load'.format(0))
plt.legend()
plt.show()
print ('Simulation completed')