npmitchell, the following code seems to work:
from mshr import *
from dolfin import *
class LeftBoundary(SubDomain):
def inside(self, x, on_boundary):
tol = DOLFIN_EPS
return on_boundary and abs(x[0]) < tol
class RightBoundary(SubDomain):
def inside(self, x, on_boundary):
tol = DOLFIN_EPS
return on_boundary and abs(x[0] - 1) < tol
E , nu = 1.0, 0.4 #J/m^3, unitless
mesh = UnitSquareMesh(100, 100)
Vv = VectorFunctionSpace(mesh, "Lagrange", 1)
Vf = FunctionSpace(mesh, "Lagrange", 1)
Vt = TensorFunctionSpace(mesh, "Lagrange", 1)
Q = VectorFunctionSpace(mesh, 'R', 0, 3)
W = MixedFunctionSpace([Vv, Q])
u, p = TrialFunctions(W)
tau, q = TestFunctions(W)
left_boundary = LeftBoundary()
right_boundary = RightBoundary()
boundary_parts = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundary_parts.set_all(0)
left_boundary.mark(boundary_parts, 1)
right_boundary.mark(boundary_parts, 2)
ds = Measure("ds")[boundary_parts]
P1 = Constant((-1, 0))
P2 = Constant((1, 0))
d = u.geometric_dimension()
epsilon = sym(grad(u))
sigma = E/(1+nu)* (epsilon) + E*nu/((1-nu**2)) * tr(epsilon)*Identity(d)
trans = [Constant((1, 0)), Constant((0, 1))]
rota = [Expression(('-x[1]', 'x[0]'))]
n = trans+rota
## Solve force balance
a = inner(sigma, sym(grad(tau)))*dx - sum(p[i]*inner(tau, n[i])*dx for i in range(len(n)))\
-sum(q[i]*inner(u, n[i])*dx for i in range(len(n)))
L = dot(P1,tau)*ds(1) + dot(P2,tau)*ds(2)
A, b = assemble_system(a, L)
u = Function(W)
solve(A, u.vector(), b)
uh, nh = u.split()
## View the result
sigma = E/(1+nu)* (sym(grad(uh))) + E*nu/((1-nu**2)) * tr(sym(grad(uh)))*Identity(d)
s_V = project( sigma, Vt)
sxx = project(s_V[0,0], Vf); sxxv = sxx.vector().array()
sxy = project(s_V[0,1], Vf); sxyv = sxy.vector().array()
syx = project(s_V[1,0], Vf); syxv = syx.vector().array()
syy = project(s_V[1,1], Vf); syyv = syy.vector().array()
plot(sxx, interactive=True)
plot(syy, interactive=True)
I introduced the Langrange multiplier to assure the uniqueness of $u$ (block both translation and rotation of rigid body motion).
I found this interesting discussion. You can build a null space and pass it to PETSc solver in Fenics!
Thanks to MiroK