Source code for fenicsx_pulse.material_models.saint_venant_kirchhoff
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
import ufl
from .. import exceptions
from ..material_model import HyperElasticMaterial
from ..units import Variable
[docs]
@dataclass(slots=True)
class SaintVenantKirchhoff(HyperElasticMaterial):
r"""
Class for Saint Venant-Kirchhoff material
Let
.. math::
\epsilon = \frac{1}{2} ( \nabla u + \nabla u^T + \nabla u + \nabla u^T )
Then
.. math
\psi(F) = \frac{\lambda}{2} \mathrm{tr} \left( \epsilon \right)^2
+ \mu \mathrm{tr} \left( \epsilon \cdot \epsilon \right)
Parameters
----------
mu: float | dolfinx.fem.Function | dolfinx.fem.Constant
Shear modulus
lmbda: float | dolfinx.fem.Function | dolfinx.fem.Constant
Lame parameter
"""
mu: Variable
lmbda: Variable
def __post_init__(self):
# Check that all values are positive
if not isinstance(self.mu, Variable):
self.mu = Variable(self.mu, "dimensionless")
if not isinstance(self.lmbda, Variable):
self.lmbda = Variable(self.lmbda, "dimensionless")
if not exceptions.check_value_greater_than(
self.mu.value,
0.0,
inclusive=True,
):
raise exceptions.InvalidRangeError(
name="mu",
expected_range=(0.0, np.inf),
)
[docs]
def strain_energy(self, F: ufl.core.expr.Expr) -> ufl.core.expr.Expr:
dim = ufl.domain.find_geometric_dimension(F)
gradu = F - ufl.Identity(dim)
epsilon = 0.5 * (gradu + gradu.T)
mu = self.mu.to_base_units()
lmbda = self.lmbda.to_base_units()
return lmbda / 2 * (ufl.tr(epsilon) ** 2) + mu * ufl.tr(
epsilon * epsilon,
)