Source code for hyperelastic.frameworks._invariants

import numpy as np

from ..math import cdya, ddot, det, dya, eye, inv, trace


[docs] class Invariants: r"""The Framework for a Total-Lagrangian invariant-based isotropic hyperelastic material formulation provides the material behaviour-independent parts for evaluating the second Piola-Kirchhoff stress tensor as well as its associated fourth-order elasticity tensor. The gradient as well as the hessian of the strain energy function are carried out w.r.t. the right Cauchy-Green deformation tensor. Hence, the work-conjugate stress tensor is one half of the second Piola-Kirchhoff stress tensor and the fourth-order elasticitiy tensor used here is a quarter of the Total-Lagrangian elasticity tensor. .. math:: \psi(\boldsymbol{C}) = \psi(I_1(\boldsymbol{C}), I_2(\boldsymbol{C}), I_3(\boldsymbol{C})) The first and second invariants of the left or right Cauchy-Green deformation tensor are identified as factors of their characteristic polynomial, .. math:: I_1 &= \text{tr}(\boldsymbol{C}) I_2 &= \frac{1}{2} \left( \text{tr}(\boldsymbol{C})^2 - \text{tr}(\boldsymbol{C}^2) \right) I_3 &= \det(\boldsymbol{C}) where the Cauchy-Green deformation tensors eliminate the rigid body rotations of the deformation gradient and serve as a quadratic change-of-length measure of the deformation. .. math:: \boldsymbol{C} &= \boldsymbol{F}^T \boldsymbol{F} \boldsymbol{b} &= \boldsymbol{F} \boldsymbol{F}^T The first partial derivatives of the strain energy function w.r.t. the invariants .. math:: \psi_{,1} &= \frac{\partial \psi}{\partial I_1} \psi_{,2} &= \frac{\partial \psi}{\partial I_2} \psi_{,3} &= \frac{\partial \psi}{\partial I_3} and the partial derivatives of the invariants w.r.t. the right Cauchy-Green deformation tensor are defined. .. math:: \frac{\partial I_1}{\partial \boldsymbol{C}} &= \boldsymbol{I} \frac{\partial I_2}{\partial \boldsymbol{C}} &= \left( I_1 \boldsymbol{I} - \boldsymbol{C} \right) \frac{\partial I_3}{\partial \boldsymbol{C}} &= I_3 \boldsymbol{C}^{-1} The second Piola-Kirchhoff stress tensor is formulated by the application of the chain rule. .. math:: \frac{\partial \psi}{\partial \boldsymbol{C}} = \frac{\partial \psi}{\partial I_1} \frac{\partial I_1}{\partial \boldsymbol{C}} + \frac{\partial \psi}{\partial I_2} \frac{\partial I_2}{\partial \boldsymbol{C}} + \frac{\partial \psi}{\partial I_3} \frac{\partial I_3}{\partial \boldsymbol{C}} Furthermore, the second partial derivatives of the elasticity tensor are carried out. .. math:: \frac{\partial^2 \psi}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} &= \frac{\partial^2 \psi}{\partial I_1~\partial I_1} \left( \frac{\partial I_1}{\partial \boldsymbol{C}} \otimes \frac{\partial I_1}{\partial \boldsymbol{C}} \right) &+ \frac{\partial^2 \psi}{\partial I_2~\partial I_2} \left( \frac{\partial I_2}{\partial \boldsymbol{C}} \otimes \frac{\partial I_2}{\partial \boldsymbol{C}} \right) &+ \frac{\partial^2 \psi}{\partial I_3~\partial I_3} \left( \frac{\partial I_3}{\partial \boldsymbol{C}} \otimes \frac{\partial I_3}{\partial \boldsymbol{C}} \right) &+ \frac{\partial^2 \psi}{\partial I_1~\partial I_2} \left( \frac{\partial I_1}{\partial \boldsymbol{C}} \otimes \frac{\partial I_2}{\partial \boldsymbol{C}} + \frac{\partial I_2}{\partial \boldsymbol{C}} \otimes \frac{\partial I_1}{\partial \boldsymbol{C}} \right) &+ \frac{\partial^2 \psi}{\partial I_2~\partial I_3} \left( \frac{\partial I_2}{\partial \boldsymbol{C}} \otimes \frac{\partial I_3}{\partial \boldsymbol{C}} + \frac{\partial I_3}{\partial \boldsymbol{C}} \otimes \frac{\partial I_2}{\partial \boldsymbol{C}} \right) &+ \frac{\partial^2 \psi}{\partial I_1~\partial I_3} \left( \frac{\partial I_1}{\partial \boldsymbol{C}} \otimes \frac{\partial I_3}{\partial \boldsymbol{C}} + \frac{\partial I_3}{\partial \boldsymbol{C}} \otimes \frac{\partial I_1}{\partial \boldsymbol{C}} \right) &+ \frac{\partial \psi}{\partial I_1} \frac{\partial^2 I_1}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} + \frac{\partial \psi}{\partial I_2} \frac{\partial^2 I_2}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} + \frac{\partial \psi}{\partial I_3} \frac{\partial^2 I_3}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} The only non material behaviour-related terms which are not already defined during stress evaluation are the second partial derivatives of the invariants w.r.t. the right Cauchy-Green deformation tensor. .. math:: \frac{\partial^2 I_1}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} &= \mathbb{0} \frac{\partial^2 I_2}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} &= \boldsymbol{I} \otimes \boldsymbol{I} - \boldsymbol{I} \odot \boldsymbol{I} \frac{\partial^2 I_3}{\partial \boldsymbol{C}~\partial \boldsymbol{C}} &= I_3 \left( \boldsymbol{C}^{-1} \otimes \boldsymbol{C}^{-1} - \boldsymbol{C}^{-1} \odot \boldsymbol{C}^{-1} \right) """ def __init__(self, material, nstatevars=0, parallel=False): """Initialize the Framework for an invariant-based isotropic hyperelastic material formulation.""" self.parallel = parallel self.material = material self.x = [np.eye(3), np.zeros(nstatevars)]
[docs] def gradient(self, C, statevars): """The gradient as the partial derivative of the strain energy function w.r.t. the right Cauchy-Green deformation tensor (one half of the second Piola Kirchhoff stress tensor).""" self.I = I = eye(C) self.I1 = I1 = trace(C) self.I2 = (I1**2 - ddot(C, C)) / 2 self.I3 = I3 = det(C) self.dWdI1, self.dWdI2, self.dWdI3, statevars_new = self.material.gradient( self.I1, self.I2, self.I3, statevars ) ntrax = len(C.shape[1:]) dWdC = np.zeros((6, *np.ones(ntrax, dtype=int))) if self.dWdI1 is not None: self.dI1dC = I dWdC = dWdC + self.dWdI1 * self.dI1dC if self.dWdI2 is not None: self.dI2dC = I1 * I - C dWdC = dWdC + self.dWdI2 * self.dI2dC if self.dWdI3 is not None: self.invC = invC = inv(C, determinant=self.I3) self.dI3dC = I3 * invC dWdC = dWdC + self.dWdI3 * self.dI3dC return dWdC, statevars_new
[docs] def hessian(self, C, statevars): """The hessian as the second partial derivatives of the strain energy function w.r.t. the right Cauchy-Green deformation tensor (a quarter of the Lagrangian fourth-order elasticity tensor associated to the second Piola-Kirchhoff stress tensor).""" dWdC, statevars = self.gradient(C, statevars) ( d2WdI1dI1, d2WdI2dI2, d2WdI3dI3, d2WdI1dI2, d2WdI2dI3, d2WdI1dI3, ) = self.material.hessian(self.I1, self.I2, self.I3, statevars) I = self.I ntrax = len(C.shape[1:]) d2WdCdC = np.zeros((6, 6, *np.ones(ntrax, dtype=int))) if self.dWdI1 is not None: dI1dC = self.dI1dC # d2I1dCdC = 0 # d2WdCdC = d2WdCdC + self.dWdI1 * d2I1dCdC if self.dWdI2 is not None: dI2dC = self.dI2dC d2I2dCdC = dya(I, I) - cdya(I, I) d2WdCdC = d2WdCdC + self.dWdI2 * d2I2dCdC if self.dWdI3 is not None: dI3dC = self.dI3dC invC = self.invC d2I3dCdC = self.I3 * (dya(invC, invC) - cdya(invC, invC)) d2WdCdC = d2WdCdC + self.dWdI3 * d2I3dCdC if d2WdI1dI1 is not None: d2WdCdC = d2WdCdC + d2WdI1dI1 * dya(dI1dC, dI1dC) if d2WdI2dI2 is not None: d2WdCdC = d2WdCdC + d2WdI2dI2 * dya(dI2dC, dI2dC) if d2WdI3dI3 is not None: d2WdCdC = d2WdCdC + d2WdI2dI2 * dya(dI2dC, dI2dC) if d2WdI1dI2 is not None: d2WdCdC = d2WdCdC + d2WdI1dI2 * (dya(dI1dC, dI2dC) + dya(dI2dC, dI1dC)) if d2WdI2dI3 is not None: d2WdCdC = d2WdCdC + d2WdI2dI3 * (dya(dI2dC, dI3dC) + dya(dI3dC, dI2dC)) if d2WdI1dI3 is not None: d2WdCdC = d2WdCdC + d2WdI1dI3 * (dya(dI1dC, dI3dC) + dya(dI3dC, dI1dC)) return d2WdCdC