Elasticipy.tensors.fourth_order
- class elasticipy.tensors.fourth_order.FourthOrderTensor(M, mapping=<elasticipy.tensors.mapping.KelvinMapping object>, check_minor_symmetry=True, force_minor_symmetry=False)[source]
Bases:
objectTemplate class for manipulating symmetric fourth-order tensors.
Construct of Fourth-order tensor with minor symmetry.
- Parameters:
M (np.ndarray or FourthOrderTensor) – (…,6,6) matrix corresponding to the stiffness tensor, written using the Voigt notation, or array of shape (…,3,3,3,3).
mapping (MappingConvention, optional) – Mapping convention to translate the (3,3,3,3) array to (6,6) matrix.
check_minor_symmetry (bool, optional) – If true (default), check that the input array have minor symmetries (see Notes). Only used if an array of shape (…,3,3,3,3) is passed.
force_minor_symmetry – Ensure that the tensor displays minor symmetry.
Notes
The minor symmetry is defined so that:
\[M_{ijkl}=M_{jikl}=M_{jilk}=M_{ijlk}\]Given a generic 4th-order tensor T, the corresponding matrix with respect to Kelvin convention is:
\[\begin{split}T = \begin{bmatrix} T_{1111} & T_{1122} & T_{1133} & \sqrt{2}T_{1123} & \sqrt{2}T_{1113} & \sqrt{2}T_{1112}\\ T_{2211} & T_{2222} & T_{2233} & \sqrt{2}T_{2223} & \sqrt{2}T_{2213} & \sqrt{2}T_{2212}\\ T_{3311} & T_{3322} & T_{3333} & \sqrt{2}T_{3323} & \sqrt{2}T_{3313} & \sqrt{2}T_{3312}\\ \sqrt{2}T_{2311} & \sqrt{2}T_{2322} & \sqrt{2}T_{2333} & 2T_{2323} & 2T_{2313} & 2T_{2312}\\ \sqrt{2}T_{1311} & \sqrt{2}T_{1322} & \sqrt{2}T_{1333} & 2T_{423} & 2T_{1313} & 2T_{1312}\\ \sqrt{2}T_{1211} & \sqrt{2}T_{1222} & \sqrt{2}T_{1233} & 2T_{1223} & 2T_{1223} & 2T_{1212}\\ \end{bmatrix}\end{split}\]Examples
Consider a Fourth-order tensor, whose Kelvin matrix is:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> import numpy as np >>> mat = np.array([[100, 200, 300, 0, 0, 0], ... [-200, 100, 50, 0, 0, 0], ... [-300, -50, 100, 0, 0, 0], ... [0, 0, 0, 150, 0, 0], ... [0, 0, 0, 0, 150, 0], ... [0, 0, 0, 0, 0, 150]]) >>> T = FourthOrderTensor(mat) >>> print(T) 4th-order tensor (in Kelvin mapping): [[ 100. 200. 300. 0. 0. 0.] [-200. 100. 50. 0. 0. 0.] [-300. -50. 100. 0. 0. 0.] [ 0. 0. 0. 150. 0. 0.] [ 0. 0. 0. 0. 150. 0.] [ 0. 0. 0. 0. 0. 150.]]
If one wants to evaluate the tensor as a (full) (3,3,3,3) array:
>>> T_array = T.full_tensor
For instance:
>>> print(T_array[0,0,0,0]) 100.0
whereas
>>> print(T_array[0,1,0,1]) # Corresponds to T_{66}/2 75.0
The half factor comes from the Kelvin mapping convention (see Notes). One can also use the Voigt mapping to avoid this:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> T_voigt = FourthOrderTensor(mat, mapping=VoigtMapping()) >>> print(T_voigt) 4th-order tensor (in Voigt mapping): [[ 100. 200. 300. 0. 0. 0.] [-200. 100. 50. 0. 0. 0.] [-300. -50. 100. 0. 0. 0.] [ 0. 0. 0. 150. 0. 0.] [ 0. 0. 0. 0. 150. 0.] [ 0. 0. 0. 0. 0. 150.]]
Although T and T_voigt appear to be the same, note that they are not expressed using the same mapping convention. Indeed:
>>> print(T_voigt.full_tensor[0,0,0,0]) 100.0
whereas
>>> print(T_voigt.full_tensor[0,1,0,1]) 150.0
Alternatively, the differences can be checked with:
>>> print(T == T_voigt) False
Conversely, let consider the following Voigt matrix:
>>> mat = np.array([[100, 200, 300, 0, 0, 0], ... [-200, 100, 50, 0, 0, 0], ... [-300, -50, 100, 0, 0, 0], ... [0, 0, 0, 75, 0, 0], ... [0, 0, 0, 0, 75, 0], ... [0, 0, 0, 0, 0, 75]]) >>> T_voigt2 = FourthOrderTensor(mat, mapping=VoigtMapping()) >>> print(T_voigt2) 4th-order tensor (in Voigt mapping): [[ 100. 200. 300. 0. 0. 0.] [-200. 100. 50. 0. 0. 0.] [-300. -50. 100. 0. 0. 0.] [ 0. 0. 0. 75. 0. 0.] [ 0. 0. 0. 0. 75. 0.] [ 0. 0. 0. 0. 0. 75.]]
Although T and T_voigt2 are not written using the same mapping, we can compare them:
>>> print(T == T_voigt2) # Same tensors, but different mapping True
whereas
>>> print(T == T_voigt) # Different tensors, but same mapping False
This property comes from the fact that the comparison is made independently of the underlying mapping convention.
- ddot(other, mode='pair')[source]
Perform tensor product contracted twice (“:”) between two fourth-order tensors
- Parameters:
other (FourthOrderTensor or SecondOrderTensor) – Right-hand side of “:” symbol
mode (str, optional) – If mode==”pair”, the tensors must be broadcastable, and the tensor product are performed on the last axes. If mode==”cross”, all cross-combinations are considered.
- Returns:
Result from double-contraction
- Return type:
Examples
First, let consider two random arrays of Fourth-order tensors:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T1 = FourthOrderTensor.rand(shape=(2,3)) >>> T2 = FourthOrderTensor.rand(shape=3) >>> T1T2_pair = T1.ddot(T2) >>> T1T2_pair 4th-order tensor array of shape (2, 3)
whereas:
>>> T1T2_cross = T1.ddot(T2, mode='cross') >>> T1T2_cross 4th-order tensor array of shape (2, 3, 3)
The command above is equivalent (but way faster) to:
>>> T1T2_cross_loop = FourthOrderTensor.zeros(shape=(2,3,3)) >>> for i in range(2): ... for j in range(3): ... for k in range(3): ... T1T2_cross_loop[i,j,k] = T1[i,j].ddot(T2[k])
One can check that the results are consistent with:
>>> T1T2_cross_loop == T1T2_cross array([[[ True, True, True], [ True, True, True], [ True, True, True]], [[ True, True, True], [ True, True, True], [ True, True, True]]])
- deviatoric_part()[source]
Return the deviatoric part of the tensor
- Returns:
Deviatoric part of the tensor
- Return type:
See also
identity_tensorreturn the identity tensor
spherical_partreturn the spherical part of the tensor
- classmethod eye(shape=(), **kwargs)[source]
Create a 4th-order identity tensor.
See notes for definition.
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
mapping (Kelvin mapping, optional) – Mapping convention to use. Must be either Kelvin or Voigt.
- Returns:
Identity tensor
- Return type:
Notes
The Fourth-order identity tensor is defined as:
\[I_{ijkl} = \frac12\left( \delta_{ik}\delta_{jl} + \delta_{il}\delta_{jk}\right)\]Examples
Create a (single) identity tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> I = FourthOrderTensor.eye() >>> print(I) 4th-order tensor (in Kelvin mapping): [[1. 0. 0. 0. 0. 0.] [0. 1. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0.] [0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 1.]]
Alternatively, one can use another mapping convention, e.g. Voigt:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> Iv = FourthOrderTensor.eye(mapping=VoigtMapping()) >>> print(Iv) 4th-order tensor (in Voigt mapping): [[1. 0. 0. 0. 0. 0. ] [0. 1. 0. 0. 0. 0. ] [0. 0. 1. 0. 0. 0. ] [0. 0. 0. 0.5 0. 0. ] [0. 0. 0. 0. 0.5 0. ] [0. 0. 0. 0. 0. 0.5]]
Still, we have:
>>> print(I == Iv) True
as they correspond to the same tensor, but expressed as a matrix with different mapping conventions. Indeed, one can check that:
>>> import numpy as np >>> np.array_equal(I.full_tensor, Iv.full_tensor) True
- flatten()[source]
Flatten the tensor
If the tensor array is of shape (m,n,o…,r), the flattened array will be of shape (m*n*o*…*r,).
- Returns:
Flattened tensor
- Return type:
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand(shape=(5,6)) >>> T 4th-order tensor array of shape (5, 6) >>> T.flatten() 4th-order tensor array of shape (30,)
- property full_tensor[source]
Returns the full (unvoigted) tensor as a (3, 3, 3, 3) or (…, 3, 3, 3, 3) array
- Returns:
Full tensor (4-index notation)
- Return type:
np.ndarray
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> I = FourthOrderTensor.eye() # 4th order identity tensor >>> print(I) 4th-order tensor (in Kelvin mapping): [[1. 0. 0. 0. 0. 0.] [0. 1. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0.] [0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 1.]]
>>> I_full = I.full_tensor >>> type(I_full) <class 'numpy.ndarray'> >>> I_full.shape (3, 3, 3, 3)
When working on tensor arrays, the shape of the resulting numpy array will change accordlingly. E.g.:
>>> I_array = FourthOrderTensor.eye(shape=(5,6)) # Array of 4th order identity tensor >>> I_array.full_tensor.shape (5, 6, 3, 3, 3, 3)
- classmethod identity(**kwargs)[source]
Construct the Fourth-order identity tensor.
This is actually an alias for eye().
- Parameters:
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Return type:
See also
eyeFourth-order identity tensor
- classmethod identity_deviatoric_part(**kwargs)[source]
Return the deviatoric part of the identity tensor.
See notes for the mathematical definition.
- Parameters:
kwargs – keyword arguments passed to eye constructor
- Return type:
FourthOrderTensor or SymmetricTensor
See also
identity_tensorreturn the identity tensor
identity_spherical_partreturn the spherical part of the identity tensor
Notes
The deviatoric part of the identity tensor is defined as:
\[K = I - J\]where \(I\) and \(J\) denote the identity and the deviatoric part of the identity tensor, respectively.
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> K = FourthOrderTensor.identity_deviatoric_part() >>> print(K) 4th-order tensor (in Kelvin mapping): [[ 0.66666667 -0.33333333 -0.33333333 0. 0. 0. ] [-0.33333333 0.66666667 -0.33333333 0. 0. 0. ] [-0.33333333 -0.33333333 0.66666667 0. 0. 0. ] [ 0. 0. 0. 1. 0. 0. ] [ 0. 0. 0. 0. 1. 0. ] [ 0. 0. 0. 0. 0. 1. ]]
One can check that K has zero spherical part:
>>> print(K.spherical_part()) 4th-order tensor (in Kelvin mapping): [[2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
- classmethod identity_spherical_part(shape=(), **kwargs)[source]
Return the spherical part of the identity tensor.
See Notes for mathematical definition.
- Parameters:
shape (tuple of int, optional) – Shape of the tensor to create
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Return type:
See also
identity_tensorreturn the identity tensor
identity_deviatoric_partreturn the deviatoric part of the identity tensor
Notes
The spherical part of the identity tensor is defined as:
\[J_{ijkl} = \frac13 \delta_{ij}\delta_{kl}\]Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> J = FourthOrderTensor.identity_spherical_part() >>> print(J) 4th-order tensor (in Kelvin mapping): [[0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ]]
On can check that J has zero deviatoric part:
>>> J.deviatoric_part() 4th-order tensor (in Kelvin mapping): [[2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
- inv()[source]
Invert the tensor. The inverted tensors inherits the properties (if any)
- Returns:
Inverse tensor
- Return type:
Examples
Let consider a random Fourth-order tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand() >>> print(T)
>>> Tinv = T.inv() >>> print(Tinv)
One can check that
T.ddot(Tinv)andTinv.ddot(T)are really close to the identity tensor:>>> I = FourthOrderTensor.eye() >>> (T.ddot(Tinv) - I) * 1e16 4th-order tensor (in Kelvin mapping): [[ 1.00000000e+00 0.00000000e+00 1.11022302e-16 0.00000000e+00 3.14018492e-16 0.00000000e+00] [-2.22044605e-16 1.00000000e+00 2.77555756e-17 -1.25607397e-15 2.35513869e-16 -7.85046229e-17] [ 1.55431223e-15 0.00000000e+00 1.00000000e+00 -3.14018492e-16 0.00000000e+00 -4.71027738e-16] [-6.28036983e-16 -4.39625888e-15 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.11022302e-16] [-1.25607397e-15 -4.39625888e-15 0.00000000e+00 2.55351296e-15 1.00000000e+00 -1.66533454e-16] [-5.88784672e-16 -1.17756934e-15 -2.62499833e-16 5.96744876e-16 1.24900090e-16 1.00000000e+00]]
>>> (Tinv.ddot(T) - I) * 1e16 4th-order tensor (in Kelvin mapping): [[ 1.00000000e+00 -1.33226763e-15 -3.99680289e-15 -6.90840682e-15 -7.53644380e-15 -2.51214793e-15] [ 2.33146835e-15 1.00000000e+00 1.55431223e-15 -7.85046229e-16 1.41308321e-15 9.42055475e-16] [ 3.88578059e-16 1.11022302e-16 1.00000000e+00 -3.92523115e-16 -1.57009246e-16 1.57009246e-16] [-5.88784672e-17 -1.86448479e-16 -1.47196168e-16 1.00000000e+00 -2.49800181e-16 -2.08166817e-16] [ 5.10280049e-16 7.85046229e-17 -7.85046229e-17 1.27675648e-15 1.00000000e+00 7.77156117e-16] [-7.85046229e-16 -6.28036983e-16 6.28036983e-16 2.44249065e-15 3.55271368e-15 1.00000000e+00]]
This function obvisouly also works for tensor arrays. E.g.:
>>> T = FourthOrderTensor.rand(shape=(5,3)) >>> Tinv = T.inv() >>> Tinv.shape (5, 3)
Again, one can check that
T.ddot(Tinv)is close to the array of identity tensors:>>> import numpy as np >>> I = FourthOrderTensor.eye(shape=(5,3)) >>> np.max(T.ddot(Tinv).matrix() - I.matrix()) 5.906386491005833e-14
- matrix(mapping_convention=None)[source]
Returns the components of the tensor as a matrix.
- Parameters:
mapping_convention (VoigtMapping, optional) – Mapping convention to use for the returned matrix. If not provided, that of the tensor is used.
- Returns:
Components of the tensor as a matrix
- Return type:
numpy.ndarray
Examples
Create an identity 4th-order tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> t = FourthOrderTensor.eye()
Its matrix with respect to Kelvin mapping is:
>>> t.matrix() array([[1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 1.]])
whereas, when using the Voigt mapping, we have:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> t.matrix(mapping_convention=VoigtMapping()) array([[1. , 0. , 0. , 0. , 0. , 0. ], [0. , 1. , 0. , 0. , 0. , 0. ], [0. , 0. , 1. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.5, 0. , 0. ], [0. , 0. , 0. , 0. , 0.5, 0. ], [0. , 0. , 0. , 0. , 0. , 0.5]])
For stiffness tensors, the default mapping convention is Voigt, so that:
>>> from elasticipy.tensors.elasticity import StiffnessTensor, ComplianceTensor >>> StiffnessTensor.eye().matrix() array([[1. , 0. , 0. , 0. , 0. , 0. ], [0. , 1. , 0. , 0. , 0. , 0. ], [0. , 0. , 1. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.5, 0. , 0. ], [0. , 0. , 0. , 0. , 0.5, 0. ], [0. , 0. , 0. , 0. , 0. , 0.5]])
whereas for compliance tensor, the default mapping convention gives:
>>> ComplianceTensor.eye().matrix() array([[1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 2., 0., 0.], [0., 0., 0., 0., 2., 0.], [0., 0., 0., 0., 0., 2.]])
- mean(axis=None)[source]
Compute the mean value of the tensor T
- Parameters:
axis (int or list of int or tuple of int, optional) – axis along which to compute the mean. If None, the mean is computed on the flattened tensor
- Returns:
If no axis is given, the result will be of shape (3,3,3,3).
- Return type:
numpy.ndarray
Examples
Create a random tensor array of shape (5,6):
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand(shape=(5,6)) >>> Overall_mean = T.mean() >>> Overall_mean.shape () >>> Overall_mean 4th-order tensor (in Kelvin mapping): [[0.514295 0.52259217 0.42899181 0.77148692 0.64073221 0.73211491] [0.49422678 0.43718365 0.40786118 0.8170971 0.68435571 0.67262655] [0.48753674 0.51142541 0.44650454 0.76310921 0.67724973 0.69430165] [0.53946846 0.75101474 0.73578098 1.04338905 1.21598419 0.99489014] [0.75354555 0.61193555 0.82341479 1.11197826 0.89183143 1.20986243] [0.66078807 0.70126535 0.63719147 0.87567139 1.05671229 1.03004098]]
>>> axis_0_mean = T.mean(axis=0) >>> axis_0_mean.shape (6,) >>> axis_1_mean = T.mean(axis=1) >>> axis_1_mean.shape (5,)
- property ndim[source]
Returns the dimensionality of the tensor (number of dimensions in the orientation array)
- Returns:
Number of dimensions
- Return type:
int
- classmethod ones(shape=None, **kwargs)[source]
Create a 4th-order tensor full of ones.
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
kwargs – keyword arguments passed to the constructor
- Return type:
Examples
>>> tensor_of_ones = FourthOrderTensor.ones() >>> tensor_of_ones 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
At first sight, the tensor may appear not full of ones at all, but the representation above uses the Kelvin mapping convention. Indeed, one can check that the full tensor is actually full of ones. E.g.:
>>> tensor_of_ones.full_tensor[0,1,0,2] np.float64(1.0)
Alternatively, the Voigt mapping convention may help figuring it out:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> tensor_of_ones_voigt = FourthOrderTensor.ones(mapping=VoigtMapping()) >>> tensor_of_ones_voigt 4th-order tensor (in Voigt mapping): [[1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.]]
although both tensors are actually the same:
>>> print(tensor_of_ones == tensor_of_ones_voigt) True
- classmethod rand(shape=None, **kwargs)[source]
Populate a Fourth-order tensor with random values in half-open interval [0.0, 1.0).
- Parameters:
shape (tuple or int, optional) – Set the shape of the tensor array. If None, the returned tensor will be single.
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Returns:
Fourth-order tensor
- Return type:
- rotate(rotation)[source]
Apply a single rotation to a tensor, and return its component into the rotated frame.
- Parameters:
rotation (Rotation or orix.quaternion.rotation.Rotation) – Rotation to apply
- Returns:
Rotated tensor
- Return type:
Examples
Let start from a given tensor, (say ones):
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.ones() >>> T 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
Define a rotation. E.g.:
>>> from scipy.spatial.transform import Rotation >>> g = Rotation.from_euler('X', 90, degrees=True)
Then , apply rotation:
>>> Trotated = T.rotate(g) >>> Trotated 4th-order tensor (in Kelvin mapping): [[ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ] [ 1.41421356 1.41421356 1.41421356 -2. 2. -2. ] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ]]
Actually, a more simple syntax is:
>>> T * g 4th-order tensor (in Kelvin mapping): [[ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ] [ 1.41421356 1.41421356 1.41421356 -2. 2. -2. ] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ]]
Obviously, the original tensor can be retrieved by applying the reverse rotation:
>>> Trotated * g.inv() 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
If
gis composed of multiple rotations, this will result in a tensor array, corresponding to each rotation:>>> import numpy as np >>> theta = np.linspace(0, 90, 100) >>> g = Rotation.from_euler('X', theta, degrees=True) >>> Trotated = T * g >>> Trotated 4th-order tensor array of shape (100,)
- property shape[source]
Return the shape of the tensor array
- Returns:
Shape of the tensor array
- Return type:
tuple
- spherical_part()[source]
Return the spherical part of the tensor
- Returns:
Spherical part of the tensor
- Return type:
See also
identity_tensorreturn the identity tensor
deviatoric_partreturn the deviatoric part of the tensor
- tensor_average(weights=None, axis=0)[source]
Compute the average of a tensor array.
- Parameters:
weights (list of float or tuple of floats, optional) – If provided, each tensor value is weighted accordingly
axis (int, optional) – Axis to compute the average over (default: 0)
- Return type:
- transpose_array()[source]
Transpose the orientations of the tensor array
- Returns:
The same tensor, but with transposed axes
- Return type:
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> A = FourthOrderTensor.rand(shape=(3,4)) >>> A.transpose_array() 4th-order tensor array of shape (4, 3)
- classmethod zeros(shape=(), **kwargs)[source]
Create a fourth-order tensor populated with zeros
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
kwargs – Keyword arguments passed to the FourthOrderTensor constructor
- Return type:
Examples
The single-valued null 4th order tensor is just:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> FourthOrderTensor.zeros() 4th-order tensor (in Kelvin mapping): [[0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.]]
One can also create an array of such tensors:
>>> zeros_tensor = FourthOrderTensor.zeros(shape=3)
and check that it populated with zeros:
>>> zeros_tensor == 0. array([ True, True, True])
- class elasticipy.tensors.fourth_order.SymmetricFourthOrderTensor(M, check_symmetries=True, force_symmetries=False, **kwargs)[source]
Bases:
FourthOrderTensorConstruct a fully symmetric fourth-order tensor from a (…,6,6) or a (…,3,3,3,3) array.
The input matrix must be symmetric, otherwise an error is thrown (except if
check_symmetry==False, see below)- Parameters:
M (np.ndarray or FourthOrderTensor) – (6,6) matrix corresponding to the stiffness tensor, or slices of (6,6) matrices or array of shape (…,3,3,3,3).
check_symmetries (bool, optional) – Whether to check or not that the tensor to built displays both major and minor symmetries (see Notes).
force_symmetries (bool, optional) – If true, ensure that the tensor displays both minor and major symmetries.
Notes
The major symmetry is defined so that:
\[M_{ijkl}=M_{klij}\]whereas the minor symmetry is:
\[M_{ijkl}=M_{jikl}=M_{jilk}=M_{ijlk}\]- ddot(other, mode='pair')[source]
Perform tensor product contracted twice (“:”) between two fourth-order tensors
- Parameters:
other (FourthOrderTensor or SecondOrderTensor) – Right-hand side of “:” symbol
mode (str, optional) – If mode==”pair”, the tensors must be broadcastable, and the tensor product are performed on the last axes. If mode==”cross”, all cross-combinations are considered.
- Returns:
Result from double-contraction
- Return type:
Examples
First, let consider two random arrays of Fourth-order tensors:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T1 = FourthOrderTensor.rand(shape=(2,3)) >>> T2 = FourthOrderTensor.rand(shape=3) >>> T1T2_pair = T1.ddot(T2) >>> T1T2_pair 4th-order tensor array of shape (2, 3)
whereas:
>>> T1T2_cross = T1.ddot(T2, mode='cross') >>> T1T2_cross 4th-order tensor array of shape (2, 3, 3)
The command above is equivalent (but way faster) to:
>>> T1T2_cross_loop = FourthOrderTensor.zeros(shape=(2,3,3)) >>> for i in range(2): ... for j in range(3): ... for k in range(3): ... T1T2_cross_loop[i,j,k] = T1[i,j].ddot(T2[k])
One can check that the results are consistent with:
>>> T1T2_cross_loop == T1T2_cross array([[[ True, True, True], [ True, True, True], [ True, True, True]], [[ True, True, True], [ True, True, True], [ True, True, True]]])
- deviatoric_part()[source]
Return the deviatoric part of the tensor
- Returns:
Deviatoric part of the tensor
- Return type:
See also
identity_tensorreturn the identity tensor
spherical_partreturn the spherical part of the tensor
- classmethod eye(shape=(), **kwargs)[source]
Create a 4th-order identity tensor.
See notes for definition.
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
mapping (Kelvin mapping, optional) – Mapping convention to use. Must be either Kelvin or Voigt.
- Returns:
Identity tensor
- Return type:
Notes
The Fourth-order identity tensor is defined as:
\[I_{ijkl} = \frac12\left( \delta_{ik}\delta_{jl} + \delta_{il}\delta_{jk}\right)\]Examples
Create a (single) identity tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> I = FourthOrderTensor.eye() >>> print(I) 4th-order tensor (in Kelvin mapping): [[1. 0. 0. 0. 0. 0.] [0. 1. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0.] [0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 1.]]
Alternatively, one can use another mapping convention, e.g. Voigt:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> Iv = FourthOrderTensor.eye(mapping=VoigtMapping()) >>> print(Iv) 4th-order tensor (in Voigt mapping): [[1. 0. 0. 0. 0. 0. ] [0. 1. 0. 0. 0. 0. ] [0. 0. 1. 0. 0. 0. ] [0. 0. 0. 0.5 0. 0. ] [0. 0. 0. 0. 0.5 0. ] [0. 0. 0. 0. 0. 0.5]]
Still, we have:
>>> print(I == Iv) True
as they correspond to the same tensor, but expressed as a matrix with different mapping conventions. Indeed, one can check that:
>>> import numpy as np >>> np.array_equal(I.full_tensor, Iv.full_tensor) True
- flatten()[source]
Flatten the tensor
If the tensor array is of shape (m,n,o…,r), the flattened array will be of shape (m*n*o*…*r,).
- Returns:
Flattened tensor
- Return type:
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand(shape=(5,6)) >>> T 4th-order tensor array of shape (5, 6) >>> T.flatten() 4th-order tensor array of shape (30,)
- property full_tensor[source]
Returns the full (unvoigted) tensor as a (3, 3, 3, 3) or (…, 3, 3, 3, 3) array
- Returns:
Full tensor (4-index notation)
- Return type:
np.ndarray
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> I = FourthOrderTensor.eye() # 4th order identity tensor >>> print(I) 4th-order tensor (in Kelvin mapping): [[1. 0. 0. 0. 0. 0.] [0. 1. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0.] [0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 1.]]
>>> I_full = I.full_tensor >>> type(I_full) <class 'numpy.ndarray'> >>> I_full.shape (3, 3, 3, 3)
When working on tensor arrays, the shape of the resulting numpy array will change accordlingly. E.g.:
>>> I_array = FourthOrderTensor.eye(shape=(5,6)) # Array of 4th order identity tensor >>> I_array.full_tensor.shape (5, 6, 3, 3, 3, 3)
- classmethod identity(**kwargs)[source]
Construct the Fourth-order identity tensor.
This is actually an alias for eye().
- Parameters:
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Return type:
See also
eyeFourth-order identity tensor
- classmethod identity_deviatoric_part(**kwargs)[source]
Return the deviatoric part of the identity tensor.
See notes for the mathematical definition.
- Parameters:
kwargs – keyword arguments passed to eye constructor
- Return type:
FourthOrderTensor or SymmetricTensor
See also
identity_tensorreturn the identity tensor
identity_spherical_partreturn the spherical part of the identity tensor
Notes
The deviatoric part of the identity tensor is defined as:
\[K = I - J\]where \(I\) and \(J\) denote the identity and the deviatoric part of the identity tensor, respectively.
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> K = FourthOrderTensor.identity_deviatoric_part() >>> print(K) 4th-order tensor (in Kelvin mapping): [[ 0.66666667 -0.33333333 -0.33333333 0. 0. 0. ] [-0.33333333 0.66666667 -0.33333333 0. 0. 0. ] [-0.33333333 -0.33333333 0.66666667 0. 0. 0. ] [ 0. 0. 0. 1. 0. 0. ] [ 0. 0. 0. 0. 1. 0. ] [ 0. 0. 0. 0. 0. 1. ]]
One can check that K has zero spherical part:
>>> print(K.spherical_part()) 4th-order tensor (in Kelvin mapping): [[2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
- classmethod identity_spherical_part(shape=(), **kwargs)[source]
Return the spherical part of the identity tensor.
See Notes for mathematical definition.
- Parameters:
shape (tuple of int, optional) – Shape of the tensor to create
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Return type:
See also
identity_tensorreturn the identity tensor
identity_deviatoric_partreturn the deviatoric part of the identity tensor
Notes
The spherical part of the identity tensor is defined as:
\[J_{ijkl} = \frac13 \delta_{ij}\delta_{kl}\]Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> J = FourthOrderTensor.identity_spherical_part() >>> print(J) 4th-order tensor (in Kelvin mapping): [[0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0.33333333 0.33333333 0.33333333 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ] [0. 0. 0. 0. 0. 0. ]]
On can check that J has zero deviatoric part:
>>> J.deviatoric_part() 4th-order tensor (in Kelvin mapping): [[2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [2.77555756e-17 2.77555756e-17 2.77555756e-17 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
- infinite_random_average()[source]
Compute the average of the tensor, assuming that an infinite number of random orientations is applied.
- Returns:
Average tensor or tensor array. The returned array will be of the same shape as the input object.
- Return type:
- inv()[source]
Invert the tensor. The inverted tensors inherits the properties (if any)
- Returns:
Inverse tensor
- Return type:
Examples
Let consider a random Fourth-order tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand() >>> print(T)
>>> Tinv = T.inv() >>> print(Tinv)
One can check that
T.ddot(Tinv)andTinv.ddot(T)are really close to the identity tensor:>>> I = FourthOrderTensor.eye() >>> (T.ddot(Tinv) - I) * 1e16 4th-order tensor (in Kelvin mapping): [[ 1.00000000e+00 0.00000000e+00 1.11022302e-16 0.00000000e+00 3.14018492e-16 0.00000000e+00] [-2.22044605e-16 1.00000000e+00 2.77555756e-17 -1.25607397e-15 2.35513869e-16 -7.85046229e-17] [ 1.55431223e-15 0.00000000e+00 1.00000000e+00 -3.14018492e-16 0.00000000e+00 -4.71027738e-16] [-6.28036983e-16 -4.39625888e-15 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.11022302e-16] [-1.25607397e-15 -4.39625888e-15 0.00000000e+00 2.55351296e-15 1.00000000e+00 -1.66533454e-16] [-5.88784672e-16 -1.17756934e-15 -2.62499833e-16 5.96744876e-16 1.24900090e-16 1.00000000e+00]]
>>> (Tinv.ddot(T) - I) * 1e16 4th-order tensor (in Kelvin mapping): [[ 1.00000000e+00 -1.33226763e-15 -3.99680289e-15 -6.90840682e-15 -7.53644380e-15 -2.51214793e-15] [ 2.33146835e-15 1.00000000e+00 1.55431223e-15 -7.85046229e-16 1.41308321e-15 9.42055475e-16] [ 3.88578059e-16 1.11022302e-16 1.00000000e+00 -3.92523115e-16 -1.57009246e-16 1.57009246e-16] [-5.88784672e-17 -1.86448479e-16 -1.47196168e-16 1.00000000e+00 -2.49800181e-16 -2.08166817e-16] [ 5.10280049e-16 7.85046229e-17 -7.85046229e-17 1.27675648e-15 1.00000000e+00 7.77156117e-16] [-7.85046229e-16 -6.28036983e-16 6.28036983e-16 2.44249065e-15 3.55271368e-15 1.00000000e+00]]
This function obvisouly also works for tensor arrays. E.g.:
>>> T = FourthOrderTensor.rand(shape=(5,3)) >>> Tinv = T.inv() >>> Tinv.shape (5, 3)
Again, one can check that
T.ddot(Tinv)is close to the array of identity tensors:>>> import numpy as np >>> I = FourthOrderTensor.eye(shape=(5,3)) >>> np.max(T.ddot(Tinv).matrix() - I.matrix()) 5.906386491005833e-14
- linear_invariants()[source]
Compute the linear invariants of the tensor, or tensor array.
If the object is a tensor array, the linear invariants are returned as arrays of each invariant. See notes for the actual definitions.
- Returns:
A1 (float or np.ndarray) – First linear invariant
A2 (float or np.ndarray) – Second linear invariant
See also
quadratic_invariantscompute the quadratic invariants of a fourth-order tensor
Notes
The linear invariants are:
\[ \begin{align}\begin{aligned}A_1=C_{ijij}\\A_2=C_{iijj}\end{aligned}\end{align} \]
- matrix(mapping_convention=None)[source]
Returns the components of the tensor as a matrix.
- Parameters:
mapping_convention (VoigtMapping, optional) – Mapping convention to use for the returned matrix. If not provided, that of the tensor is used.
- Returns:
Components of the tensor as a matrix
- Return type:
numpy.ndarray
Examples
Create an identity 4th-order tensor:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> t = FourthOrderTensor.eye()
Its matrix with respect to Kelvin mapping is:
>>> t.matrix() array([[1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 1.]])
whereas, when using the Voigt mapping, we have:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> t.matrix(mapping_convention=VoigtMapping()) array([[1. , 0. , 0. , 0. , 0. , 0. ], [0. , 1. , 0. , 0. , 0. , 0. ], [0. , 0. , 1. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.5, 0. , 0. ], [0. , 0. , 0. , 0. , 0.5, 0. ], [0. , 0. , 0. , 0. , 0. , 0.5]])
For stiffness tensors, the default mapping convention is Voigt, so that:
>>> from elasticipy.tensors.elasticity import StiffnessTensor, ComplianceTensor >>> StiffnessTensor.eye().matrix() array([[1. , 0. , 0. , 0. , 0. , 0. ], [0. , 1. , 0. , 0. , 0. , 0. ], [0. , 0. , 1. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.5, 0. , 0. ], [0. , 0. , 0. , 0. , 0.5, 0. ], [0. , 0. , 0. , 0. , 0. , 0.5]])
whereas for compliance tensor, the default mapping convention gives:
>>> ComplianceTensor.eye().matrix() array([[1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 2., 0., 0.], [0., 0., 0., 0., 2., 0.], [0., 0., 0., 0., 0., 2.]])
- mean(axis=None)[source]
Compute the mean value of the tensor T
- Parameters:
axis (int or list of int or tuple of int, optional) – axis along which to compute the mean. If None, the mean is computed on the flattened tensor
- Returns:
If no axis is given, the result will be of shape (3,3,3,3).
- Return type:
numpy.ndarray
Examples
Create a random tensor array of shape (5,6):
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.rand(shape=(5,6)) >>> Overall_mean = T.mean() >>> Overall_mean.shape () >>> Overall_mean 4th-order tensor (in Kelvin mapping): [[0.514295 0.52259217 0.42899181 0.77148692 0.64073221 0.73211491] [0.49422678 0.43718365 0.40786118 0.8170971 0.68435571 0.67262655] [0.48753674 0.51142541 0.44650454 0.76310921 0.67724973 0.69430165] [0.53946846 0.75101474 0.73578098 1.04338905 1.21598419 0.99489014] [0.75354555 0.61193555 0.82341479 1.11197826 0.89183143 1.20986243] [0.66078807 0.70126535 0.63719147 0.87567139 1.05671229 1.03004098]]
>>> axis_0_mean = T.mean(axis=0) >>> axis_0_mean.shape (6,) >>> axis_1_mean = T.mean(axis=1) >>> axis_1_mean.shape (5,)
- property ndim[source]
Returns the dimensionality of the tensor (number of dimensions in the orientation array)
- Returns:
Number of dimensions
- Return type:
int
- classmethod ones(shape=None, **kwargs)[source]
Create a 4th-order tensor full of ones.
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
kwargs – keyword arguments passed to the constructor
- Return type:
Examples
>>> tensor_of_ones = FourthOrderTensor.ones() >>> tensor_of_ones 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
At first sight, the tensor may appear not full of ones at all, but the representation above uses the Kelvin mapping convention. Indeed, one can check that the full tensor is actually full of ones. E.g.:
>>> tensor_of_ones.full_tensor[0,1,0,2] np.float64(1.0)
Alternatively, the Voigt mapping convention may help figuring it out:
>>> from elasticipy.tensors.mapping import VoigtMapping >>> tensor_of_ones_voigt = FourthOrderTensor.ones(mapping=VoigtMapping()) >>> tensor_of_ones_voigt 4th-order tensor (in Voigt mapping): [[1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.]]
although both tensors are actually the same:
>>> print(tensor_of_ones == tensor_of_ones_voigt) True
- quadratic_invariants()[source]
Compute the quadratic invariants of the tensor, or tensor array.
If the object is a tensor array, the returned values are arrays of each invariant. See notes for definitions.
- Returns:
B1, B2, B3, B4, B5
- Return type:
float or np.ndarray
See also
linear_invariantscompute the linear invariants of a Fourth-order tensor
Notes
The quadratic invariants are defined as [Norris]:
\[ \begin{align}\begin{aligned}B_1 = C_{ijkl}C_{ijkl}\\B_2 = C_{iikl}C_{jjkl}\\B_3 = C_{iikl}C_{jkjl}\\B_4 = C_{kiil}C_{kjjl}\\B_5 = C_{ijkl}C_{ikjl}\end{aligned}\end{align} \]References
[Norris]Norris, A. N. (22 May 2007). “Quadratic invariants of elastic moduli”. The Quarterly Journal of Mechanics and Applied Mathematics. 60 (3): 367–389. doi:10.1093/qjmam/hbm007
- classmethod rand(shape=None, **kwargs)[source]
Populate a Fourth-order tensor with random values in half-open interval [0.0, 1.0).
- Parameters:
shape (tuple or int, optional) – Set the shape of the tensor array. If None, the returned tensor will be single.
kwargs – Keyword arguments passed to the Fourth-order tensor constructor.
- Returns:
Fourth-order tensor
- Return type:
- rotate(rotation)[source]
Apply a single rotation to a tensor, and return its component into the rotated frame.
- Parameters:
rotation (Rotation or orix.quaternion.rotation.Rotation) – Rotation to apply
- Returns:
Rotated tensor
- Return type:
Examples
Let start from a given tensor, (say ones):
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> T = FourthOrderTensor.ones() >>> T 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
Define a rotation. E.g.:
>>> from scipy.spatial.transform import Rotation >>> g = Rotation.from_euler('X', 90, degrees=True)
Then , apply rotation:
>>> Trotated = T.rotate(g) >>> Trotated 4th-order tensor (in Kelvin mapping): [[ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ] [ 1.41421356 1.41421356 1.41421356 -2. 2. -2. ] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ]]
Actually, a more simple syntax is:
>>> T * g 4th-order tensor (in Kelvin mapping): [[ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [ 1. 1. 1. -1.41421356 1.41421356 -1.41421356] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ] [ 1.41421356 1.41421356 1.41421356 -2. 2. -2. ] [-1.41421356 -1.41421356 -1.41421356 2. -2. 2. ]]
Obviously, the original tensor can be retrieved by applying the reverse rotation:
>>> Trotated * g.inv() 4th-order tensor (in Kelvin mapping): [[1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1. 1. 1. 1.41421356 1.41421356 1.41421356] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ] [1.41421356 1.41421356 1.41421356 2. 2. 2. ]]
If
gis composed of multiple rotations, this will result in a tensor array, corresponding to each rotation:>>> import numpy as np >>> theta = np.linspace(0, 90, 100) >>> g = Rotation.from_euler('X', theta, degrees=True) >>> Trotated = T * g >>> Trotated 4th-order tensor array of shape (100,)
- property shape[source]
Return the shape of the tensor array
- Returns:
Shape of the tensor array
- Return type:
tuple
- spherical_part()[source]
Return the spherical part of the tensor
- Returns:
Spherical part of the tensor
- Return type:
See also
identity_tensorreturn the identity tensor
deviatoric_partreturn the deviatoric part of the tensor
- tensor_average(weights=None, axis=0)[source]
Compute the average of a tensor array.
- Parameters:
weights (list of float or tuple of floats, optional) – If provided, each tensor value is weighted accordingly
axis (int, optional) – Axis to compute the average over (default: 0)
- Return type:
- transpose_array()[source]
Transpose the orientations of the tensor array
- Returns:
The same tensor, but with transposed axes
- Return type:
Examples
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> A = FourthOrderTensor.rand(shape=(3,4)) >>> A.transpose_array() 4th-order tensor array of shape (4, 3)
- classmethod zeros(shape=(), **kwargs)[source]
Create a fourth-order tensor populated with zeros
- Parameters:
shape (int or tuple, optional) – Shape of the tensor to create
kwargs – Keyword arguments passed to the FourthOrderTensor constructor
- Return type:
Examples
The single-valued null 4th order tensor is just:
>>> from elasticipy.tensors.fourth_order import FourthOrderTensor >>> FourthOrderTensor.zeros() 4th-order tensor (in Kelvin mapping): [[0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0.]]
One can also create an array of such tensors:
>>> zeros_tensor = FourthOrderTensor.zeros(shape=3)
and check that it populated with zeros:
>>> zeros_tensor == 0. array([ True, True, True])