I am answering my own question so that a working code is available:
Code for eigenvalue decomposition:
from dolfin import *
import sympy as sp
import numpy as np
import numpy.linalg as LA
#----------------------------------------------------------------------#
# set some dolfin specific parameters
parameters["form_compiler"]["optimize"] = True
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["representation"] = 'uflacs'
#----------------------------------------------------------------------#
#----------------------------------------------------------------------#
# Compute the symbolic expression for eigenvalues by sympy
T = sp.Matrix(2, 2, lambda i, j: sp.Symbol('T[%d, %d]' % (i, j), symmetric =True, real=True))
eig_expr = T.eigenvects() # ((v, multiplicity, [w])...)
#eig_expr = T.LDLdecomposition()
eigv = [e[0] for e in eig_expr]
eigw = [e[-1][0] for e in eig_expr]
eigv = sp.Matrix(eigv) # Column vector
eigw = sp.Matrix(eigw) # Row has the elements
eigw = sp.Matrix([[eigw[0],eigw[2]],[eigw[1],eigw[3]]])
eigv = sp.Matrix([[eigv[0], 0.0],[0.0, eigv[1]]])
eigv_expr = map(str, eigv)
eigw_expr = map(str, eigw)
#----------------------------------------------------------------------#
#----------------------------------------------------------------------#
# Create UFL operators for the eigenvalues and eigenvectors
# UFL operator for eigenvalues of 2x2 matrix, a pair of scalars
def eigv(T): return map(eval, eigv_expr)
# UFL operator for eigenvectors of 2x2 matrix, a pair of vectors
def eigw(T): return map(eval, eigw_expr)
#----------------------------------------------------------------------#
spd = 2 # Spatial dimension
n = 16 # Size of mesh
mesh = UnitSquareMesh(n, n)
V = VectorFunctionSpace(mesh, 'CG', 1) # V = TensorFunctionSpace(mesh, 'CG', 1) -> Original
x = SpatialCoordinate(mesh)
# Define variational problem
du = TrialFunction(V)
delta_u = TestFunction(V)
# set up solution functions
uh = Function(V,name='displacement')
# The way the eigenvalues are computed we cannot allow a constant value of u at start
uh_array = uh.vector().array()
uh_array = np.random.rand(len(uh_array))
uh.vector()[:] = uh_array
force = Constant((0., -1.0))
T = Constant((0., 0.))
# Define boundary condition
tol = 1E-14
def clamped_boundary(x, on_boundary):
return on_boundary and x[0] < tol
bc = DirichletBC(V, Constant((0, 0)), clamped_boundary)
def eps(u):
return sym(grad(u))
def strn(u):
t = sym(grad(u))
v00, v01, v10, v11 = eigv(t)
w00, w01, w10, w11 = eigw(t)
w = ([w00,w01],[w10,w11])
w = as_tensor(w)
v = ([v00,v01],[v10,v11])
v = as_tensor(v)
return w*v*inv(w)
# Positive strain
def strn_p(u):
t = sym(grad(u))
v00, v01, v10, v11 = eigv(t)
v00 = conditional(gt(v00,0.0),v00,0.0)
v11 = conditional(gt(v11,0.0),v11,0.0)
w00, w01, w10, w11 = eigw(t)
wp = ([w00,w01],[w10,w11])
wp = as_tensor(wp)
vp = ([v00,v01],[v10,v11])
vp = as_tensor(vp)
return wp*vp*inv(wp)
# Negative strain
def strn_n(u):
t = sym(grad(u))
v00, v01, v10, v11 = eigv(t)
v00 = conditional(lt(v00,0.0),v00,0.0)
v11 = conditional(lt(v11,0.0),v11,0.0)
w00, w01, w10, w11 = eigw(t)
wn = ([w00,w01],[w10,w11])
wn = as_tensor(wn)
vn = ([v00,v01],[v10,v11])
vn = as_tensor(vn)
return wn*vn*inv(wn)
lmbda = 10.0
mu = 1.0
def sigma(u):
#return lmbda*(tr(eps(u)))*Identity(spd) +2*mu*eps(u)
# To compare the answers
return lmbda*(tr(strn_p(u)+strn_n(u)))*Identity(spd) +2.0*mu*(strn_p(u)+strn_n(u))
F_u = inner(sigma(uh),grad(delta_u))*dx + dot(force, delta_u)*dx
J_u = derivative(F_u, uh, du )
# Compute solution
problem = NonlinearVariationalProblem(F_u, uh, bc, J_u)
solver = NonlinearVariationalSolver(problem)
solver.solve()
V = FunctionSpace(mesh, 'CG', 1)
# Compute magnitude of displacement
u_magnitude = sqrt(dot(uh, uh))
u_magnitude = project(u_magnitude, V)
#plot(u_magnitude, 'Displacement magnitude')
# Any suggestions?
print('min/max u:',
u_magnitude.vector().array().min(),
u_magnitude.vector().array().max())
#----------------------------------------------------------------------#
# A simple 2-D elasticity problem ends here.
# The solution obtained was:
# ('min/max u:', -5.0591841289798924e-05, 0.9251112919755422)
#
# Reconstructing the strain gives:
#('min/max u:', -5.0591841289772903e-05, 0.92511129197543296)
# Obtaining the values manually and solving gives me the same answer.
#----------------------------------------------------------------------#