This is a read only copy of the old FEniCS QA forum. Please visit the new QA forum to ask questions

Jacobian of nonlinear time-dependent variational problem with Expression

0 votes

Hello,

I'm quite new to FEniCS and so far I'm very impressed, especially with the documentation and ease of use of the software.

As part of my PhD project I'm trying to develop a model of soft tissue swelling. The material is hyperelastic and the swelling is modelled using a multiplicative split of the deformation gradient into swelling and elastic components. At this stage the swelling is defined by a simple function of time using an "Expression" (later it may depend on other variables or an external subroutine).

The model converges quickly when only standard boundary conditions such as forces and displacements are applied. However, when I apply the swelling deformation the model fails to converge unless pseudo-timestepping with relatively small time steps is used. Therefore, I suspect that there is either a problem with the linearisation of the swelling part of the model (the Jacobian) or that the swelling introduces significant nonlinearities that can only be overcome by taking small time steps.

My question is: do I need to modify the Jacobian to account for the Expression that is changing with time or is this done automatically by FEniCS? In other words, is there any way that I can improve the convergence of the solution.

Here is an example of the code I have so far:

from dolfin import *

# Optimization options for the form compiler
parameters["form_compiler"]["cpp_optimize"] = True
ffc_options = {"optimize": True, \
               "eliminate_zeros": True, \
               "precompute_basis_const": True, \
               "precompute_ip_const": True,
               "quadrature_degree": 1}

# Create mesh and define function space
mesh = UnitCubeMesh(24, 16, 16)
V = VectorFunctionSpace(mesh, "Lagrange", 1)

# 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

# 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
l = Expression(("0.0", "0.0", "0.0"))
r = Expression(("0.0", "0.0", "0.0"))
bcl = DirichletBC(V, l, left)
bcr = DirichletBC(V, r, right)
bcs = [bcl, bcr]

d = u.geometric_dimension()
I = Identity(d)             # Identity tensor

# Swelling
Fs = Expression(("1 + scale*t"), t=0.0, scale = 0.5)
Fsinv = 1 / Fs
Js = Fs ** 3

# Kinematics
F = I + grad(u)             # Deformation gradient
Fe = F * Fsinv              # Elastic deformation gradient
Ce = Fe.T * Fe              # Elastic right Cauchy-Green tensor

# Invariants of deformation tensors
Ice = variable(tr(Ce))
Je  = variable(det(Fe))

# Elasticity parameters
E, nu = 10.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)*(Ice - 3) - mu*ln(Je) + (lmbda/2)*(ln(Je))**2

# Elastic second Piola-Kirchhoff stress tensor
Se = 2*diff(psi, Ice)*I + Je*Je*diff(psi, Je)*inv(Ce)

# Total second Piola-Kirchhoff stress
S = Js * Fsinv * Se * Fsinv

# First Piola-Kirchhoff stress tensor
P = F*S

# Variational problem
F = inner(P, grad(v))*dx - inner(B, v)*dx - inner(T, v)*ds

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

# Timestepping
t = 0.0; dt = 0.1; T = 1.0
inc = 0
file = File("displacement.pvd");
file << u
while t < T:
    t += dt
    inc += 1

    # Update swelling deformation
    Fs.t = t

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

    # Save solution in VTK format
    file << u;

# Plot and hold solution
plot(u, mode = "displacement", interactive = True)
asked Aug 31, 2015 by benzwick FEniCS Novice (350 points)

1 Answer

0 votes
 
Best answer

I don't see any problems here for derivative(), so I'm guessing your convergence problems are either a bug in your model or a tough model.

However if your Expression will later depend on u through an external computation, that will not be picked up by derivative(). What you can do then is to specify the partial derivative "d(Fs)/du" as a Function dFs that you compute yourself somehow, and pass it to derivative as derivative(F, u, du, coefficient_derivatives={Fs:dFs}).

answered Sep 4, 2015 by martinal FEniCS User (2,800 points)
selected Sep 5, 2015 by benzwick

An unrelated suggestion: Your model is quite complex. Have you tried uflacs? That should reduce your form compilation time significantly.

To use it, set
parameters["form_compiler"]["representation"] = "uflacs"
and drop ffc_options.

If it's not already installed, you could try installing the latest dev versions of fenics from source.

Thank you very much. You're right, there was at least one bug in the model and it's also a difficult problem to solve. I think I fixed it now---the results and convergence compare very well with Abaqus.

I'd heard good things about uflacs but wasn't using it yet because I had some trouble installing the latest version of FEniCS. I followed your suggestion and it's made a massive difference to the assembly speed.

...