Mixed formulation for Incompressible Hyperelasticity
See original GitHub issueFollowing #439 and inputs from ex18, I started working yesterday on a mixed formulation for incompressible hyperelasticity using the Taylor-Hood elements. The idea is to work on imposing Dirichlet BC’s later today and then test a simple uniaxial tension later in the week. This should be fairly self contained. This is what I have so far. Please let me know whenever you get time to take a look. No rush from my end
from numpy import einsum, linalg as nla, zeros, zeros_like, concatenate, abs as npabs, split as npsplit
from scipy.sparse import bmat
from sympy import Symbol, simplify, lambdify, diff, sqrt
from skfem.helpers import grad, transpose
from typing import List, Optional
from numba import jit, prange
from skfem import *
@jit(cache=True, nopython=True, nogil=True, parallel=True)
def vdet(A):
detA = zeros_like(A[0, 0])
detA = A[0, 0] * (A[1, 1] * A[2, 2] -
A[1, 2] * A[2, 1]) -\
A[0, 1] * (A[1, 0] * A[2, 2] -
A[1, 2] * A[2, 0]) +\
A[0, 2] * (A[1, 0] * A[2, 1] -
A[1, 1] * A[2, 0])
return detA
@jit(cache=True, nopython=True, nogil=True, parallel=True)
def vinv(A):
invA = zeros_like(A)
detA = vdet(A)
invA[0, 0] = (-A[1, 2] * A[2, 1] +
A[1, 1] * A[2, 2]) / detA
invA[1, 0] = (A[1, 2] * A[2, 0] -
A[1, 0] * A[2, 2]) / detA
invA[2, 0] = (-A[1, 1] * A[2, 0] +
A[1, 0] * A[2, 1]) / detA
invA[0, 1] = (A[0, 2] * A[2, 1] -
A[0, 1] * A[2, 2]) / detA
invA[1, 1] = (-A[0, 2] * A[2, 0] +
A[0, 0] * A[2, 2]) / detA
invA[2, 1] = (A[0, 1] * A[2, 0] -
A[0, 0] * A[2, 1]) / detA
invA[0, 2] = (-A[0, 2] * A[1, 1] +
A[0, 1] * A[1, 2]) / detA
invA[1, 2] = (A[0, 2] * A[1, 0] -
A[0, 0] * A[1, 2]) / detA
invA[2, 2] = (-A[0, 1] * A[1, 0] +
A[0, 0] * A[1, 1]) / detA
return invA, detA
def F1(w):
u = w["w"][0]
p = w["w"][1]
# print(w["w"][0])
F = zeros_like(grad(u))
for i in prange(3):
F[i,i] += 1.
F += grad(u)
Finv, J = vinv(F)
return p * J * transpose(Finv) + mu * F
def F2(w):
u = w["w"][0]
p = w["w"][1]
F = zeros_like(grad(u))
for i in prange(3):
F[i,i] += 1.
F += grad(u)
J = vdet(F)
Js = Jstar(p)
return J-(Js + (p + mu/Js - lmbda*(Js - 1))*dJst_dp(p))
def A11(w):
u = w["w"][0]
p = w["w"][1]
F = zeros_like(grad(u))
eye = zeros_like(grad(u))
for i in prange(3):
F[i,i] += 1.
eye[i,i] += 1.
F += grad(u)
Finv, J = vinv(F)
L = p*J*einsum("lk...,ji...->ijkl...",Finv, Finv) - p * J * einsum("jk...,li...->ijkl...", Finv, Finv) + mu * einsum("ik...,jl...->ijkl...", eye, eye)
return L
def A12(w):
u = w["w"][0]
p = w["w"][1]
F = zeros_like(grad(u))
for i in prange(3):
F[i,i] += 1.
F += grad(u)
Finv, J = vinv(F)
return J * transpose(Finv)
def A21(w):
u = w["w"][0]
p = w["w"][1]
F = zeros_like(grad(u))
for i in prange(3):
F[i,i] += 1.
F += grad(u)
Finv, J = vinv(F)
return J * transpose(Finv)
def A22(w):
u = w["w"][0]
p = w["w"][1]
# F = zeros_like(grad(u))
# for i in prange(3):
# F[i,i] += 1.
# F += grad(u)
# Finv, J = vinv(F)
Js = Jstar(p)
dJdp = dJst_dp(p)
d2Jdp2 = d2Jst_dp2(p)
L = -2.*dJdp - p * d2Jdp2 + mu/Js**2 * dJdp**2 - mu/Js*d2Jdp2 + lmbda * (Js - 1.) * d2Jdp2 + lmbda * dJdp**2
return L
mesh = MeshTet()
uelem = ElementVectorH1(ElementTetP2())
pelem = ElementTetP1()
elems = {
"u": uelem,
"p": pelem
}
basis = {
field: InteriorBasis(mesh, e, intorder=3)
for field, e in elems.items()
}
du = zeros(basis["u"].N)
dp = zeros(basis["p"].N)
stretch_ = 1.5
dofs = {
"left":basis["u"].get_dofs(lambda x: x[0] < 1.e-6),
"bottom":basis["u"].get_dofs(lambda x: x[1] < 1.e-6),
"back":basis["u"].get_dofs(lambda x: x[2] < 1.e-6),
"front":basis["u"].get_dofs(lambda x: x[2] > 1. - 1.e-6)
}
# print(dofs)
du[dofs["left"].nodal["u^1"]] = 0.
du[dofs["bottom"].nodal["u^2"]] = 0.
du[dofs["back"].nodal["u^3"]] = 0.
du[dofs["front"].nodal["u^3"]] = stretch_
I = basis["u"].complement_dofs(dofs)
# material parameters
mu, lmbda = 1., 1.e3
p = Symbol("p", real=True)
Jst = (lmbda + p + sqrt((lmbda+p)**2 + 4*lmbda*mu ))/(2*lmbda)
dJst_dp = lambdify(p, simplify(Jst.diff(p)), "numpy")
d2Jst_dp2 = lambdify(p, simplify(Jst.diff(p,2)), "numpy")
Jstar = lambdify(p, simplify(Jst), "numpy")
w = (
basis["u"].interpolate(du),
basis["p"].interpolate(dp)
)
@LinearForm
def a1(v, w):
return einsum("ij...,ij...",F1(w), grad(v))
@LinearForm
def a2(v, w):
return F2(w) * v
@BilinearForm
def b11(u, v, w):
return einsum("ijkl...,ij...,kl...",A11(w), grad(u), grad(v))
@BilinearForm
def b12(u, v, w):
return einsum("ij...,ij...",A12(w), grad(v)) * u
@BilinearForm
def b21(u, v, w):
return einsum("ij...,ij...",A21(w), grad(v)) * u
@BilinearForm
def b22(u, v, w):
return A22(w) * u * v
for itr in range(100):
w = (
basis["u"].interpolate(du),
basis["p"].interpolate(dp)
)
K11 = asm(b11, basis["u"], basis["u"], w=w)
K12 = asm(b12, basis["p"], basis["u"], w=w)
K21 = asm(b21, basis["p"], basis["u"], w=w)
K22 = asm(b22, basis["p"], basis["p"], w=w)
f = concatenate((
asm(a1, basis["u"], w=w),
asm(a2, basis["p"], w=w)
))
K = bmat(
[[K11, K12],
[K21.T, K22]], "csr"
)
uvp = solve(*condense(K, -f, I=I), use_umfpack=True)
delu, delp = npsplit(uvp, [K11.shape[0]])
du += delu
dp += delp
normu = nla.norm(delu)
normp = nla.norm(delp)
print(f"{itr+1}, norm_du: {normu}, norm_dp: {normp}")
if normu < 1.e-6 and normp < 1.e-6:
break
import meshio
from vedo import show as vShow, Mesh as vMesh
meshio.xdmf.write(
"mixedFEM.xdmf",
meshio.Mesh(mesh.p.T, {"tetra":mesh.t.T},point_data={"u":du[basis["u"].nodal_dofs].T})
)
Once I work through the details, and it happens to be of interest to you I’d be glad to contribute it as an (advanced) example.
Issue Analytics
- State:
- Created 3 years ago
- Comments:26 (26 by maintainers)
Top Results From Across the Web
A mixed finite element formulation for compressible finite ...
Abstract. A mixed finite element formulation for compressible finite hyperelasticity, possibly with strongly deformation dependent stiffening ...
Read more >Mixed Formulation
The mixed formulation is useful not only for linear elastic materials but also for elastoplastic materials, hyperelastic materials, and viscoelastic materials.
Read more >A mixed finite element method for large deformation analysis ...
This paper discusses finite element formulations for large deformation analysis of incompressible hyperelastic materials.
Read more >A linearized consistent mixed displacement-pressure ...
Abstract. We propose a novel mixed displacement-pressure formulation based on an energy functional that takes into account the relation ...
Read more >Mixed Kirchhoff stress - displacement - pressure formulations ...
Keywords: Kirchhoff stress formulation, Incompressible hyperelasticity, Augmented Lagrangian preconditioning, Mixed finite element methods. 2000 ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I see, right now
find_dofs
(etc.) are targeted more towards finding boundary DOF’s than interior DOF’s although the keyall
may suggest something else. I still haven’t quite figured out how to design a proper interface for finding and handling DOF’s.So maybe it was something related to the DOF’s after all? I changed
to
and now I get Edit: Forgot to mention that the above uses
ElementTetMini
but I now verified that I get the same correct result withElementTetP2
.