Implementing Ex.36 from scikit-fem in FElupe #615
Replies: 6 comments 9 replies
-
FElupe also has a very similar built-in Here's the code: import felupe as fem
mesh = fem.Cube(n=5).triangulate().add_midpoints_edges()
region = fem.RegionQuadraticTetra(mesh)
field = fem.FieldsMixed(region, n=3)
boundaries, loadcase = fem.dof.uniaxial(field, clamped=False)
import tensortrax.math as tm
def ψ(C, μ, λ):
I1 = tm.trace(C)
J = tm.sqrt(tm.linalg.det(C))
lnJ = tm.log(J)
return μ / 2 * (I1 - 3) - μ * lnJ + λ / 2 * (J - 1) ** 2
umat = fem.ThreeFieldVariation(fem.Hyperelastic(ψ, μ=1, λ=1e4, parallel=True))
solid = fem.SolidBody(umat, field)
move = fem.math.linsteps([0, 1], num=5)
step = fem.Step(items=[solid], ramp={boundaries["move"]: move}, boundaries=boundaries)
job = fem.CharacteristicCurve(steps=[step], boundary=boundaries["move"])
job.evaluate(tol=1e-2)
fig, ax = job.plot(
xlabel="Displacement $u$ in mm $\longrightarrow$",
ylabel="Normal Force $F$ in N $\longrightarrow$",
)
ax2 = field.imshow("Principal Values of Logarithmic Strain") |
Beta Was this translation helpful? Give feedback.
-
The strain energy function from Ex.36 is implemented in FElupe as import felupe as fem
mesh = fem.Cube(n=5).triangulate().add_midpoints_edges()
region = fem.RegionQuadraticTetra(mesh)
field = fem.FieldsMixed(region, n=3)
boundaries, loadcase = fem.dof.uniaxial(field, clamped=False)
umat = fem.ThreeFieldVariation(fem.NeoHookeCompressible(mu=1, lmbda=1e4))
solid = fem.SolidBody(umat, field)
move = fem.math.linsteps([0, 1], num=5)
step = fem.Step(items=[solid], ramp={boundaries["move"]: move}, boundaries=boundaries)
job = fem.CharacteristicCurve(steps=[step], boundary=boundaries["move"])
job.evaluate(tol=1e-2)
fig, ax = job.plot(
xlabel="Displacement $u$ in mm $\longrightarrow$",
ylabel="Normal Force $F$ in N $\longrightarrow$",
)
ax2 = field.imshow("Principal Values of Logarithmic Strain") |
Beta Was this translation helpful? Give feedback.
-
a) For the most general approach and without all the fancy automatic differentiation stuff, please have a look at b) For a more scikit-fem approach, there is also This should be really enough to read for the beginning 😄 . |
Beta Was this translation helpful? Give feedback.
-
Great @adtzlr ! This is super helpful!! Many thanks |
Beta Was this translation helpful? Give feedback.
-
And here you can find more or less the 1:1 translation of the original code. I replaced only the math-helpers. I used import numpy as np
import felupe as fem
from felupe.math import det, inv, transpose, identity
import pypardiso
def F1(F, p, mu, lmbda):
J = det(F)
Finv = inv(F)
return p * J * transpose(Finv) + mu * F
def F2(F, p, mu, lmbda):
J = det(F)
Js = 0.5 * (lmbda + p + 2.0 * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2)) / lmbda
dJsdp = (
0.25 * lmbda + 0.25 * p + 0.5 * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2)
) / (lmbda * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2))
return J - (Js + (p + mu / Js - lmbda * (Js - 1)) * dJsdp)
def A11(F, p, mu, lmbda):
eye = identity(F)
J = det(F)
Finv = inv(F)
L = (
p * J * np.einsum("lk...,ji...->ijkl...", Finv, Finv)
- p * J * np.einsum("jk...,li...->ijkl...", Finv, Finv)
+ mu * np.einsum("ik...,jl...->ijkl...", eye, eye)
)
return L
def A12(F, p, mu, lmbda):
J = det(F)
Finv = inv(F)
return J * transpose(Finv)
def A22(F, p, mu, lmbda):
Js = 0.5 * (lmbda + p + 2.0 * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2)) / lmbda
dJsdp = (
0.25 * lmbda + 0.25 * p + 0.5 * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2)
) / (lmbda * np.sqrt(lmbda * mu + 0.25 * (lmbda + p) ** 2))
d2Jdp2 = 0.25 * mu / (lmbda * mu + 0.25 * (lmbda + p) ** 2) ** (3 / 2)
L = (
-2.0 * dJsdp
- p * d2Jdp2
+ mu / Js**2 * dJsdp**2
- mu / Js * d2Jdp2
+ lmbda * (Js - 1.0) * d2Jdp2
+ lmbda * dJsdp**2
)
return L
def stress(x, mu, lmbda):
F, p, statevars = x[0], x[1], x[-1]
return [F1(F, p, mu, lmbda), F2(F, p, mu, lmbda), statevars]
def elasticity(x, mu, lmbda):
F, p = x[0], x[1]
return [A11(F, p, mu, lmbda), A12(F, p, mu, lmbda), A22(F, p, mu, lmbda)]
mesh = fem.Cube(n=5).triangulate().add_midpoints_edges()
region_u = fem.RegionQuadraticTetra(mesh=mesh)
region_p = fem.RegionTetra(mesh=fem.mesh.dual(mesh, disconnect=False), quadrature=region_u.quadrature, grad=False)
displacement = fem.Field(region_u, dim=3)
pressure = fem.Field(region_p)
field = fem.FieldContainer([displacement, pressure])
boundaries, loadcase = fem.dof.uniaxial(field, clamped=False)
umat = fem.Material(stress, elasticity, mu=1, lmbda=1e4)
solid = fem.SolidBody(umat, field)
move = fem.math.linsteps([0, 1], num=5)
step = fem.Step(items=[solid], ramp={boundaries["move"]: move}, boundaries=boundaries)
job = fem.CharacteristicCurve(steps=[step], boundary=boundaries["move"])
job.evaluate(tol=1e-2, solver=pypardiso.spsolve)
fig, ax = job.plot(
xlabel="Displacement $u$ in mm $\longrightarrow$",
ylabel="Normal Force $F$ in N $\longrightarrow$",
)
ax2 = field.imshow("Principal Values of Logarithmic Strain") |
Beta Was this translation helpful? Give feedback.
-
mesh = fem.Cube(n=5).triangulate().add_midpoints_edges()
region_u = fem.RegionQuadraticTetra(mesh=mesh)
region_p = fem.RegionTetra(mesh=fem.mesh.dual(mesh, disconnect=False), quadrature=region_u.quadrature, grad=False)
displacement = fem.Field(region_u, dim=3)
pressure = fem.Field(region_p)
field = fem.FieldContainer([displacement, pressure]) Note: The dual mesh for the secondary field A german Wikipedia article contains a note on the instability when dealing with a disconnected mesh/field for the pressure. @bhaveshshrimali Do you know more on that topic? |
Beta Was this translation helpful? Give feedback.
-
Here are some possible implementations of Ex.36, taken from the docs of
scikit-fem
. These examples requirepip install felupe[all] matadi
to be installed.The mixed-field container automatically creates the Taylor-Hood element. The region of the first field is the one we created (
RegionQuadraticTetra
)and the second field is based on a region one order lower,
RegionTetra
- but with the quadrature scheme fromRegionQuadraticTetra
.Boundary conditions are created with a template for uniaxial tension. For more details on boundary conditions please see
Boundary
.In this first implementation, we'll use the gradients of the strain energy function, carried out by automatic differentiation using matadi.
Beta Was this translation helpful? Give feedback.
All reactions