# -*- coding: utf-8 -*-
"""
Created on Wed Apr 27 21:09:24 2022
@author: nicolas.christ@kit.edu
Tensor class for basic arithmetic operations. More information on tensor representation in Voigt and Mandel notations are given in [Brannon2018]_.
"""
import numpy as np
[docs]class Tensor:
"""
Tensor class to help with basic arithmetic operations on tensor space.
Attributes
----------
e1 : ndarray of shape (3,)
Vector 1 of orthonormalbasis of 1st order tensors.
e2 : ndarray of shape (3,)
Vector 2 of orthonormalbasis of 1st order tensors.
e3 : ndarray of shape (3,)
Vector 3 of orthonormalbasis of 1st order tensors.
B : ndarray of shape (3, 3, 6)
Orthonormalbasis of 4th order tensors in Mandel notation.
B_voigt : ndarray of shape (3, 3, 6)
Orthogonalbasis of 4th order tensors in Voigt notation.
"""
def __init__(self):
self.e1 = np.array([1, 0, 0])
self.e2 = np.array([0, 1, 0])
self.e3 = np.array([0, 0, 1])
# Orthonormalbasis 4th order tensor (Mandel)
self.B = np.zeros((3, 3, 6))
self.B[:, :, 0] = self._diade(self.e1, self.e1)
self.B[:, :, 1] = self._diade(self.e2, self.e2)
self.B[:, :, 2] = self._diade(self.e3, self.e3)
self.B[:, :, 3] = (
np.sqrt(2)
/ 2
* (self._diade(self.e2, self.e3) + self._diade(self.e3, self.e2))
)
self.B[:, :, 4] = (
np.sqrt(2)
/ 2
* (self._diade(self.e1, self.e3) + self._diade(self.e3, self.e1))
)
self.B[:, :, 5] = (
np.sqrt(2)
/ 2
* (self._diade(self.e1, self.e2) + self._diade(self.e2, self.e1))
)
# Orthogonalbasis 4th order tensor (Voigt)
self.B_voigt = np.zeros((3, 3, 6))
self.B_voigt[:, :, 0] = self._diade(self.e1, self.e1)
self.B_voigt[:, :, 1] = self._diade(self.e2, self.e2)
self.B_voigt[:, :, 2] = self._diade(self.e3, self.e3)
self.B_voigt[:, :, 3] = (self._diade(self.e2, self.e3) + self._diade(self.e3, self.e2))
self.B_voigt[:, :, 4] = (self._diade(self.e1, self.e3) + self._diade(self.e3, self.e1))
self.B_voigt[:, :, 5] = (self._diade(self.e1, self.e2) + self._diade(self.e2, self.e1))
[docs] def _diade(self, di, dj):
"""
Return diadic product of two directional vectors. This is used to
calculate the basis tensors in the Mandel notation.
Parameters
----------
di : ndarray of shape (3,)
Directional vector #1.
dj : ndarray of shape (3,)
Directional vector #2.
Returns
-------
ndarray of shape (3, 3)
Tensor of 2nd order in tensor notation.
"""
return np.einsum("i,j->ij", di, dj)
[docs] def _diade4(self, bi, bj):
"""
Return diadic product of two tensors. This is used to transfer
stiffness tensors from Mandel notation to regular tensor
notation.
Parameters
----------
bi : ndarray of shape (3, 3)
Orthonormal basis tensor #1.
bj : ndarray of shape (3, 3)
Orthonormal basis tensor #2.
Returns
-------
ndarray of shape (3, 3, 3, 3)
Tensor of 4th order in tensor notation.
"""
return np.einsum("ij,kl->ijkl", bi, bj)
[docs] def tensor_product(self, tensor_a, tensor_b):
"""
Return the mapping of one tensor of 4th order to another in the
Mandel notation.
Parameters
----------
tensor_a : ndarray of shape (6, 6)
Tensor #1.
tensor_b : ndarray of shape (6, 6)
Tensor #2.
Returns
-------
ndarray of shape (6, 6)
Resulting mapping.
"""
return np.einsum("ij,jk->ik", tensor_a, tensor_b)
[docs] def matrix2voigt(self, matrix):
"""
Return the Voigt notation of a tensor of 2nd order
calculated from the regular tensor notation.
Parameters
----------
matrix : ndarray of shape (3, 3)
Tensor of 2nd order in regular tensor notation.
Returns
-------
ndarray of shape (6,)
Tensor in Voigt notation.
"""
return np.array(
[
matrix[0, 0],
matrix[1, 1],
matrix[2, 2],
matrix[1, 2],
matrix[0, 2],
matrix[0, 1],
]
)
[docs] def matrix2mandel(self, matrix):
"""
Return the Mandel notation of a tensor of 2nd order
calculated from the regular tensor notation.
Parameters
----------
matrix : ndarray of shape (3, 3)
Tensor of 2nd order in regular tensor notation.
Returns
-------
ndarray of shape (6,)
Tensor in Mandel notation.
"""
b = np.sqrt(2)
return np.array(
[
matrix[0, 0],
matrix[1, 1],
matrix[2, 2],
b * matrix[1, 2],
b * matrix[0, 2],
b * matrix[0, 1],
]
)
[docs] def _tensor2matrix(self, tensor, representation):
"""
Return a matrix representation (either Mandel or Voigt) of a tensor
of 4th order calculated from the regular tensor notation.
Parameters
----------
tensor : ndarray of shape (3, 3, 3, 3)
Tensor of 4th order in regular tensor notation.
representation : string
Reduction type (options: 'voigt', 'mandel')
Returns
-------
ndarray of shape (6, 6)
Tensor in reduced notation.
"""
assert (
representation == "voigt" or representation == "mandel"
), "Only Mandel or Voigt notation are valid!"
if representation == "voigt":
c = 1
b = 1
else:
c = np.sqrt(2)
b = np.sqrt(2)
g = tensor
return np.array(
[
[
g[0, 0, 0, 0],
g[0, 0, 1, 1],
g[0, 0, 2, 2],
b * g[0, 0, 1, 2],
b * g[0, 0, 0, 2],
b * g[0, 0, 0, 1],
],
[
g[1, 1, 0, 0],
g[1, 1, 1, 1],
g[1, 1, 2, 2],
b * g[1, 1, 1, 2],
b * g[1, 1, 0, 2],
b * g[1, 1, 0, 1],
],
[
g[2, 2, 0, 0],
g[2, 2, 1, 1],
g[2, 2, 2, 2],
b * g[2, 2, 1, 2],
b * g[2, 2, 0, 2],
b * g[2, 2, 0, 1],
],
[
c * g[1, 2, 0, 0],
c * g[1, 2, 1, 1],
c * g[1, 2, 2, 2],
b * c * g[1, 2, 1, 2],
b * c * g[1, 2, 0, 2],
b * c * g[1, 2, 0, 1],
],
[
c * g[0, 2, 0, 0],
c * g[0, 2, 1, 1],
c * g[0, 2, 2, 2],
b * c * g[0, 2, 1, 2],
b * c * g[0, 2, 0, 2],
b * c * g[0, 2, 0, 1],
],
[
c * g[0, 1, 0, 0],
c * g[0, 1, 1, 1],
c * g[0, 1, 2, 2],
b * c * g[0, 1, 1, 2],
b * c * g[0, 1, 0, 2],
b * c * g[0, 1, 0, 1],
],
]
)
[docs] def tensor2mandel(self, tensor):
"""
Return the Mandel notation of a tensor of 4th
order calculated from the regular tensor notation.
Parameters
----------
tensor : ndarray of shape (3, 3, 3, 3)
Tensor of 4th order in regular tensor notation.
Returns
-------
ndarray of shape (6, 6)
Tensor in Mandel notation.
"""
return self._tensor2matrix(tensor, representation="mandel")
[docs] def tensor2voigt(self, tensor):
"""
Return the Voigt notation of a tensor of 4th
order calculated from the regular tensor notation.
Parameters
----------
tensor : ndarray of shape (3, 3, 3, 3)
Tensor of 4th order in regular tensor notation.
Returns
-------
ndarray of shape (6, 6)
Tensor in Mandel notation.
"""
return self._tensor2matrix(tensor, representation="voigt")
[docs] def mandel2tensor(self, mandel):
"""
Return the regular tensor notation of a tensor calculated from
the Mandel notation.
Parameters
----------
mandel : ndarray of shape (6, 6)
Tensor of 4th order in Mandel notation.
Returns
-------
tensor : ndarray of shape (3, 3, 3, 3)
Tensor in regular tensor notation.
"""
tensor = np.zeros((3, 3, 3, 3))
for i in range(0, 6):
for j in range(0, 6):
tensor += mandel[i, j] * self._diade4(self.B[:, :, i], self.B[:, :, j])
return tensor
[docs] def voigt2tensor(self, voigt):
"""
Return the regular tensor notation of a tensor calculated from
the Voigt notation.
Parameters
----------
voigt : ndarray of shape (6, 6)
Tensor of 4th order in Voigt notation.
Returns
-------
tensor : ndarray of shape (3, 3, 3, 3)
Tensor in regular tensor notation.
"""
tensor = np.zeros((3, 3, 3, 3))
for i in range(0, 6):
for j in range(0, 6):
tensor += voigt[i, j] * self._diade4(self.B_voigt[:, :, i], self.B_voigt[:, :, j])
return tensor
[docs] def mandel2voigt(self, mandel):
"""
Return the Voigt notation of a matrix based on
the Mandel notation.
Parameters
----------
mandel : ndarray of shape (6, 6)
Tensor of 4th order in Mandel notation.
Returns
-------
voigt : ndarray of shape (6, 6)
Tensor of 4th order in Voigt notation.
"""
voigt = self.tensor2voigt(self.mandel2tensor(mandel))
return voigt
[docs] def voigt2mandel(self, voigt):
"""
Return the Mandel notation of a matrix based on
the Voigt notation.
Parameters
----------
voigt : ndarray of shape (6, 6)
Tensor of 4th order in Voigt notation.
Returns
-------
mandel : ndarray of shape (6, 6)
Tensor of 4th order in Mandel notation.
"""
mandel = self.tensor2mandel(self.voigt2tensor(voigt))
return mandel