Source code for pulse.viscoelasticity
import logging
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
import ufl
from .units import Variable
logger = logging.getLogger(__name__)
[docs]
@dataclass
class ViscoElasticity(ABC):
[docs]
@abstractmethod
def strain_energy(self, C_dot) -> ufl.Form:
"""Strain energy density function.
Parameters
----------
C_dot : ufl.core.expr.Expr
The time derivative of the deformation gradient (strain rate)
Returns
-------
ufl.Form
The strain energy density function
"""
...
[docs]
def S(self, C_dot: ufl.core.expr.Expr) -> ufl.core.expr.Expr:
"""Cauchy stress tensor for the viscoelasticity model.
Parameters
----------
C_dot : ufl.core.expr.Expr
The time derivative of the deformation gradient (strain rate)
Returns
-------
ufl.core.expr.Expr
The Cauchy stress tensor
"""
return 2.0 * ufl.diff(self.strain_energy(C_dot), C_dot)
[docs]
def P(self, F_dot: ufl.core.expr.Expr | None = None) -> ufl.core.expr.Expr:
"""First Piola-Kirchhoff stress for the viscoelasticity model."""
if F_dot is None:
raise ValueError("F_dot must be provided for P calculation.")
C_dot = F_dot.T * F_dot
return ufl.diff(self.strain_energy(C_dot), F_dot)
[docs]
class NoneViscoElasticity(ViscoElasticity):
[docs]
def strain_energy(self, C_dot: ufl.core.expr.Expr) -> ufl.core.expr.Expr:
return 0.0
[docs]
@dataclass
class Viscous(ViscoElasticity):
eta: Variable = field(default_factory=lambda: Variable(1e2, "Pa s"))
def __post_init__(self):
if not isinstance(self.eta, Variable):
unit = "Pa s"
logger.warning("Setting eta to %s %s", self.eta, unit)
self.eta = Variable(self.eta, unit)
[docs]
def strain_energy(self, C_dot) -> ufl.Form:
E_dot = 0.5 * C_dot
eta = self.eta.to_base_units()
return 0.5 * eta * ufl.tr(E_dot * E_dot)
def __str__(self):
return "0.5\u03b7 tr (E_dot E_dot)"