Stress calculation returns zero value everywhere

I’m running the hyperelasticity demo here. The simulation runs fine. After obtaining the displacement, I used for following to calculate the PK stress values:

F=I+grad(u)
C=F.T*F
E=variable(0.5*(C-I))
SS=diff(psi,E)
Tv=TensorFunctionSpace(mesh, “Lagrange”, 1)
sss=Function(Tv, name=‘PK’)
sss.assign(project(SS, Tv))
print(sss.vector().norm(“l2”))

The output from the last line is zero. What did I do wrong here?

can you provide a minimal working example that we can copy and paste to demonstrate the issue?

2 Likes

I cannot reproduce this for a dummy energy (psi).

from dolfin import *
import numpy as np
mesh = UnitSquareMesh(2, 2)
V = VectorFunctionSpace(mesh, "CG", 1)
u = Function(V, name="u")

# Initialize the displacement to some random value for illustration
u.interpolate(Expression(("x[0]*x[0]", "x[1]*x[1]"), degree=1))

psi = lambda E: inner(E,E)
S_exact = lambda E: 2*E

F = Identity(len(u)) + grad(u)
E = 0.5*(F.T * F - Identity(len(u)) )
E1 = variable(E)
VS = TensorFunctionSpace(mesh, "DG", 0)
S = project(diff(psi(E1), E1), VS)
Se = project(S_exact(E), VS)
print(np.allclose(Se.vector()[:], S.vector()[:]))

As @nate said, please provide a minimal snippet that reproduces your issue. That would make it easier for others to help you

2 Likes
from dolfin import *
# Optimization options for the form compiler
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["representation"] = "uflacs"

# Create mesh and define function space
mesh = UnitCubeMesh(16, 12, 12)
V = VectorFunctionSpace(mesh, "Lagrange", 1)
Tv= TensorFunctionSpace(mesh, "Lagrange", 1)
# Mark boundary subdomians
left =  CompiledSubDomain("near(x[0], side) && on_boundary", side = 0.0)
right = CompiledSubDomain("near(x[0], side) && on_boundary", side = 1.0)

# Define Dirichlet boundary (x = 0 or x = 1)
c = Expression(("0.0", "0.0", "0.0"), degree=0)
r = Expression(("scale*0.0",
                "scale*(y0 + (x[1] - y0)*cos(theta) - (x[2] - z0)*sin(theta) - x[1])",
                "scale*(z0 + (x[1] - y0)*sin(theta) + (x[2] - z0)*cos(theta) - x[2])"),
                scale = 0.5, y0 = 0.5, z0 = 0.5, theta = pi/3, degree=2)

bcl = DirichletBC(V, c, left)
bcr = DirichletBC(V, r, right)
bcs = [bcl, bcr]

# Define functions
du = TrialFunction(V)            # Incremental displacement
v  = TestFunction(V)             # Test function
u  = Function(V)                 # Displacement from previous iteration
B  = Constant((0.0, -0.5, 0.0))  # Body force per unit volume
T  = Constant((0.1,  0.0, 0.0))  # Traction force on the boundary

# Kinematics
d = u.geometric_dimension()
I = Identity(d)             # Identity tensor
F = I + grad(u)             # Deformation gradient
C = F.T*F                   # Right Cauchy-Green tensor

# Invariants of deformation tensors
Ic = tr(C)
J  = det(F)

# Elasticity parameters
E, nu = 100.0, 0.3
mu, lmbda = Constant(E/(2*(1 + nu))), Constant(E*nu/((1 + nu)*(1 - 2*nu)))

# Stored strain energy density (compressible neo-Hookean model)
psi = (mu/2)*((Ic - 3))- mu*ln(J) + (lmbda/2)*(ln(J))**2

# Total potential energy
Pi = psi*dx - dot(B, u)*dx - dot(T, u)*ds

# Compute first variation of Pi (directional derivative about u in the direction of v)
F = derivative(Pi, u, v)

# Compute Jacobian of F
J = derivative(F, u, du)

# Solve variational problem
solve(F == 0, u, bcs, J=J)

# Save solution in VTK format


F=I+grad(u)
C=F.T*F
E=variable(0.5*(C-I))
SS=diff(psi,E)

sss=Function(Tv, name='PK')
sss.assign(project(SS, Tv))
print(sss.vector().norm("l2"))



'''

@bhaveshshrimali Here’s a slightly modified version of your dummy energy:

from dolfin import *
import numpy as np
mesh = UnitCubeMesh(5,5,5)
V = VectorFunctionSpace(mesh, "CG", 1)
u = Function(V, name="u")

# Initialize the displacement to some random value for illustration
u.interpolate(Expression(("x[0]*x[0]", "x[1]*x[1]",0), degree=1))


psi = lambda E: inner(E,E)
S_exact = lambda E: 2*E
mu, lmbda=1000.,1000.
F = Identity(len(u)) + grad(u)
E = 0.5*(F.T * F - Identity(len(u)) )
Ic=tr(F.T*F)
J=det(F)
psi1 = (mu/2)*((Ic - 3))- mu*ln(J) + (lmbda/2)*(ln(J))**2
E1 = variable(E)
VS = TensorFunctionSpace(mesh, "DG", 0)
S = project(diff(psi1, E1), VS)
print(S.vector().norm("l2")

You shouldn’t differentiate psi1 wrt F (or E). Your solution u is known after you solve the balance of linear momentum, so F would also be known and therefore psi is also completely known. You should mark the variable with respect to which you are taking the derivative and then use diff on a ufl function of that variable. For instance, for the first PK stress consider this

from dolfin import *
import numpy as np
mesh = UnitCubeMesh(5, 5, 5)
V = VectorFunctionSpace(mesh, "CG", 1)
u = Function(V, name="u")

mu, lmbda = Constant(1), Constant(5)
psi = lambda F: mu/2*(inner(F, F) - 3) - mu * ln(det(F)) + lmbda/2 * (ln(det(F)))**2
S_exact = lambda F: mu * F - mu * inv(F).T + lmbda * ln(det(F)) * inv(F).T

F = Identity(len(u)) + grad(u)
F1 = variable(F)
VS = TensorFunctionSpace(mesh, "DG", 1)
S = project(diff(psi(F1), F1), VS)
Se = project(S_exact(F), VS)
print(S.vector()[:])
print(Se.vector()[:])
assert np.linalg.norm(S.vector()[:] - Se.vector()[:], np.inf) < 1.e-8

As for the second PK stress, I would suggest writing psi explicitly in terms of E or use chain rule.

2 Likes