tensormesh.functional.elasticity 源代码


import torch 
from typing import Union
from .ops import sym,skew,sqrt,divide

[文档] def strain(gradu:torch.Tensor)->torch.Tensor: r""" .. math:: \varepsilon_{ij} = \frac{1}{2}(\nabla u_{ij} + \nabla u_{ji}), \quad \varepsilon,\nabla u \in \mathbb{R}^{d \times d} where: - :math:`\nabla u \in \mathbb{R}^{d \times d}` is the displacement gradient tensor - :math:`\varepsilon \in \mathbb{R}^{d \times d}` is the strain tensor Parameters ---------- gradu: torch.Tensor 1D Tensor of shape [d] gradient of displacement field u with respect to spatial coordinates Returns ------- torch.Tensor 2D Tensor of shape [d, d] """ return sym(gradu)
[文档] def isotropic_stress(strain:torch.Tensor, E:Union[float,torch.Tensor]=70.0, nu:Union[float,torch.Tensor] = 0.3)->torch.Tensor: r""" .. math:: \sigma_{ij} = \frac{E}{1+\nu} \left(\varepsilon_{ij} + \frac{\nu}{1-2\nu} \text{tr}(\varepsilon) \delta_{ij}\right), \quad \sigma,\varepsilon \in \mathbb{R}^{d \times d} where: - :math:`\sigma \in \mathbb{R}^{d \times d}` is the stress tensor - :math:`\varepsilon \in \mathbb{R}^{d \times d}` is the strain tensor - :math:`E \in \mathbb{R}` is Young's modulus - :math:`\nu \in \mathbb{R}` is Poisson's ratio - :math:`\delta_{ij} \in \mathbb{R}^{d \times d}` is the Kronecker delta tensor - :math:`\text{tr}: \mathbb{R}^{d \times d} \rightarrow \mathbb{R}` denotes the trace operator Parameters ---------- strain: torch.Tensor 2D Tensor of shape [d, d] strain tensor E: Union[float,torch.Tensor] if torch.Tensor, 0D Tensor of shape [] Young's modulus nu: Union[float,torch.Tensor] if torch.Tensor, 0D Tensor of shape [] Poisson's ratio Returns ------- torch.Tensor 2D Tensor of shape [d, d] """ # assertion if isinstance(E, torch.Tensor): assert E.shape == strain.shape[:-2] if isinstance(nu, torch.Tensor): assert nu.shape == strain.shape[:-2] dim = strain.shape[-1] mu = E/(2.*(1. + nu)) _lambda = E*nu/((1+nu)*(1-2*nu)) return _lambda * strain.trace().repeat(dim).diag() + 2 * mu * strain
[文档] def deviatoric_stress(stress:torch.Tensor)->torch.Tensor: r""" .. math:: s_{ij} = \sigma_{ij} - \frac{1}{d} \text{tr}(\sigma) \delta_{ij}, \quad s,\sigma \in \mathbb{R}^{d \times d} where: - :math:`s_{ij} \in \mathbb{R}^{d \times d}` is the deviatoric stress tensor - :math:`\sigma_{ij} \in \mathbb{R}^{d \times d}` is the stress tensor - :math:`d \in \mathbb{N}` is the dimension - :math:`\delta_{ij} \in \mathbb{R}^{d \times d}` is the Kronecker delta - :math:`\text{tr}: \mathbb{R}^{d \times d} \rightarrow \mathbb{R}` denotes the trace operator Parameters ---------- stress: torch.Tensor 2D Tensor of shape [d, d] stress tensor Returns ------- torch.Tensor 2D Tensor of shape [d, d] """ dim = stress.shape[-1] return stress - divide(1. , dim * stress.trace().repeat(dim).diag())
[文档] def deviatoric_stress_norm(stress:torch.Tensor)->torch.Tensor: r"""Euclidean norm of the deviatoric stress tensor. .. math:: \|s\| = \sqrt{\frac{3}{2} s:s} where :math:`s` is the deviatoric stress tensor, :math:`\|s\|` is its norm, and ``:`` denotes the double-dot product. Parameters ---------- stress: torch.Tensor 2D Tensor of shape [d, d] stress tensor Returns ------- torch.Tensor 0D Tensor of shape [] """ stress = deviatoric_stress(stress) return sqrt(1.5*(stress * stress).sum())
[文档] def voigt_shape_grad(gradu:torch.Tensor)->torch.Tensor: r""" Convert displacement gradient to Voigt notation for strain calculation. For 2D: .. math:: B \in \mathbb{R}^{3 \times (2\times 3)} = \begin{bmatrix} \frac{\partial u_1}{\partial x_1} & 0 & \mid & \frac{\partial u_2}{\partial x_1} & 0 & \mid & \frac{\partial u_3}{\partial x_1} & 0 \\ 0 & \frac{\partial u_1}{\partial x_2} & \mid & 0 & \frac{\partial u_2}{\partial x_2} & \mid & 0 & \frac{\partial u_3}{\partial x_2} \\ \frac{\partial u_1}{\partial x_2} & \frac{\partial u_1}{\partial x_1} & \mid & \frac{\partial u_2}{\partial x_2} & \frac{\partial u_2}{\partial x_1} & \mid & \frac{\partial u_3}{\partial x_2} & \frac{\partial u_3}{\partial x_1} \end{bmatrix} representing [:math:`\varepsilon_{xx}, \varepsilon_{yy}, \gamma_{xy}`] where: - :math:`u_i \in \mathbb{R}` is the displacement component in direction i - :math:`x_i \in \mathbb{R}` is the spatial coordinate in direction i - :math:`\frac{\partial u_i}{\partial x_j} \in \mathbb{R}` is the partial derivative of displacement i with respect to coordinate j For 3D: .. math:: B \in \mathbb{R}^{6 \times (3\times 3)} = \begin{bmatrix} \frac{\partial u_1}{\partial x_1} & 0 & 0 & \mid & \frac{\partial u_2}{\partial x_1} & 0 & 0 & \mid & \frac{\partial u_3}{\partial x_1} & 0 & 0 \\ 0 & \frac{\partial u_1}{\partial x_2} & 0 & \mid & 0 & \frac{\partial u_2}{\partial x_2} & 0 & \mid & 0 & \frac{\partial u_3}{\partial x_2} & 0 \\ 0 & 0 & \frac{\partial u_1}{\partial x_3} & \mid & 0 & 0 & \frac{\partial u_2}{\partial x_3} & \mid & 0 & 0 & \frac{\partial u_3}{\partial x_3} \\ 0 & \frac{\partial u_1}{\partial x_3} & \frac{\partial u_1}{\partial x_2} & \mid & 0 & \frac{\partial u_2}{\partial x_3} & \frac{\partial u_2}{\partial x_2} & \mid & 0 & \frac{\partial u_3}{\partial x_3} & \frac{\partial u_3}{\partial x_2} \\ \frac{\partial u_1}{\partial x_3} & 0 & \frac{\partial u_1}{\partial x_1} & \mid & \frac{\partial u_2}{\partial x_3} & 0 & \frac{\partial u_2}{\partial x_1} & \mid & \frac{\partial u_3}{\partial x_3} & 0 & \frac{\partial u_3}{\partial x_1} \\ \frac{\partial u_1}{\partial x_2} & \frac{\partial u_1}{\partial x_1} & 0 & \mid & \frac{\partial u_2}{\partial x_2} & \frac{\partial u_2}{\partial x_1} & 0 & \mid & \frac{\partial u_3}{\partial x_2} & \frac{\partial u_3}{\partial x_1} & 0 \end{bmatrix} representing [:math:`\varepsilon_{xx}, \varepsilon_{yy}, \varepsilon_{zz}, \gamma_{yz}, \gamma_{xz}, \gamma_{xy}`] where :math:`\varepsilon` denotes normal strain and :math:`\gamma` denotes shear strain components where: - :math:`u_i \in \mathbb{R}` is the displacement component in direction i - :math:`x_i \in \mathbb{R}` is the spatial coordinate in direction i - :math:`\frac{\partial u_i}{\partial x_j} \in \mathbb{R}` is the partial derivative of displacement i with respect to coordinate j Parameters ---------- gradu: torch.Tensor 1D Tensor of shape [d], where dim must be 2 or 3 gradient of displacement Returns ------- torch.Tensor 2D Tensor with shape [3, 2] if d=2 or [6, 3] if d=3, """ assert gradu.dim() == 1, f"gradu should be a 1D tensor of shape [dim], but got shape {gradu.shape}" dim = gradu.shape[-1] assert dim in (2, 3),f"dimension is only supported for 2, 3 for voigt shape grad, but got {dim}" a = gradu.diag() b = skew(gradu, sign=False, at_least2d=True) B = torch.cat([a, b], 0) return B
[文档] def voigt_stiffness(E:Union[float,torch.Tensor], nu:Union[float,torch.Tensor], dim:int = 2)->torch.Tensor: r""" For 2D: .. math:: \mathbb{C} \in \mathbb{R}^{3 \times 3} = \begin{bmatrix} \lambda + 2\mu & \lambda & 0 \\ \lambda & \lambda + 2\mu & 0 \\ 0 & 0 & \mu \end{bmatrix} representing [:math:`\varepsilon_{xx}, \varepsilon_{yy}, \gamma_{xy}`] For 3D: .. math:: \mathbb{C} \in \mathbb{R}^{6 \times 6} = \begin{bmatrix} \lambda + 2\mu & \lambda & \lambda & 0 & 0 & 0 \\ \lambda & \lambda + 2\mu & \lambda & 0 & 0 & 0 \\ \lambda & \lambda & \lambda + 2\mu & 0 & 0 & 0 \\ 0 & 0 & 0 & \mu & 0 & 0 \\ 0 & 0 & 0 & 0 & \mu & 0 \\ 0 & 0 & 0 & 0 & 0 & \mu \end{bmatrix} representing [:math:`\varepsilon_{xx}, \varepsilon_{yy}, \varepsilon_{zz}, \gamma_{yz}, \gamma_{xz}, \gamma_{xy}`] where: - :math:`\lambda \in \mathbb{R} = \frac{E\nu}{(1+\nu)(1-2\nu)}` - :math:`\mu \in \mathbb{R} = \frac{E}{2(1+\nu)}` Parameters ---------- E: Union[float,torch.Tensor] if torch.Tensor, 0D Tensor Young's modulus nu: float if torch.Tensor, 0D Tensor Poisson's ratio dim: int Spatial dimension of the problem (2 or 3). For 2D problems use dim=2, for 3D problems use dim=3. Default is 2. Returns ------- torch.Tensor 2D Tensor of shape :math:`[d(d+1)/2, d(d+1)/2]`, where :math:`d` is the spatial dimension """ # assertion assert dim in (2, 3) mu = E/(2.*(1. + nu)) _lambda = E*nu/((1+nu)*(1-2*nu)) if not isinstance(mu, torch.Tensor): mu = torch.tensor(mu) if not isinstance(_lambda, torch.Tensor): _lambda = torch.tensor(_lambda) if dim == 2: C = mu.repeat(3).diag() C[:2, :2] = _lambda + C[:2, :2] C[:2, :2] = mu.repeat(2).diag() + C[:2, :2] elif dim == 3: C = mu.repeat(6).diag() C[:3, :3] = _lambda + C[:3, :3] C[:3, :3] = mu.repeat(3).diag() + C[:3, :3] else: raise Exception(f"dim must be 2 or 3, but got {dim}") return C
[文档] def voigt_shape_val(u:torch.Tensor, dim:int)->torch.Tensor: r""" Convert shape functions to Voigt notation matrix for strain-displacement relations. For 2D: .. math:: N_1, N_2, N_3 \in \mathbb{R} \quad \text{(shape values)} \\ N \in \mathbb{R}^{2 \times (2\times 3)}= \begin{bmatrix} N_1 & 0 &\mid& N_2 & 0 &\mid& N_3 & 0 \\ 0 & N_1 &\mid& 0 & N_2 &\mid& 0 & N_3 \end{bmatrix} For 3D: .. math:: N_1, N_2, N_3 \in \mathbb{R} \quad \text{(shape values)} \\ N \in \mathbb{R}^{3 \times (3\times 3)}= \begin{bmatrix} N_1 & 0 & 0 &\mid& N_2 & 0 & 0 &\mid& N_3 & 0 & 0 \\ 0 & N_1 & 0 &\mid& 0 & N_2 & 0 &\mid& 0 & N_3 & 0 \\ 0 & 0 & N_1 &\mid& 0 & 0 & N_2 &\mid& 0 & 0 & N_3 \end{bmatrix} Parameters ---------- u: torch.Tensor 0D Tensor of shape [], shape value dim: int Spatial dimension. Must be 2 or 3. Returns ------- torch.Tensor 2D Tensor of shape [d, d], where :math:`d\in \{2,3\}` """ assert dim in (2, 3),f"dimension is only supported for 2, 3 for voigt shape val, but got {dim}" return u.repeat(dim).diag()