Other operators
Base.inv
Base.sqrt
Base.transpose
LinearAlgebra.cross
LinearAlgebra.det
LinearAlgebra.eigen
LinearAlgebra.eigvals
LinearAlgebra.eigvecs
LinearAlgebra.norm
LinearAlgebra.tr
Tensors.dev
Tensors.dotdot
Tensors.dott
Tensors.fromvoigt
Tensors.majorsymmetric
Tensors.majortranspose
Tensors.minorsymmetric
Tensors.minortranspose
Tensors.rotate
Tensors.rotation_tensor
Tensors.skew
Tensors.symmetric
Tensors.tdot
Tensors.tovoigt
Tensors.tovoigt!
Tensors.vol
Transpose-dot
The dot product between the transpose of a tensor with itself. Results in a symmetric tensor.
\[\mathbf{A} = \mathbf{B}^\text{T} \cdot \mathbf{B} \Leftrightarrow A_{ij} = B_{ki}^\text{T} B_{kj} = B_{ik} B_{kj}\]
\[\mathbf{A} = \mathbf{B} \cdot \mathbf{B}^\text{T} \Leftrightarrow A_{ij} = B_{ik} B_{jk}^\text{T} = B_{ik} B_{kj}\]
Tensors.tdot
— Functiontdot(A::SecondOrderTensor)
Compute the transpose-dot product of A
with itself, i.e. dot(A', A)
. Return a SymmetricTensor
.
Examples
julia> A = rand(Tensor{2,3})
3×3 Tensor{2, 3, Float64, 9}:
0.590845 0.460085 0.200586
0.766797 0.794026 0.298614
0.566237 0.854147 0.246837
julia> tdot(A)
3×3 SymmetricTensor{2, 3, Float64, 6}:
1.2577 1.36435 0.48726
1.36435 1.57172 0.540229
0.48726 0.540229 0.190334
Tensors.dott
— Functiondott(A::SecondOrderTensor)
Compute the dot-transpose product of A
with itself, i.e. dot(A, A')
. Return a SymmetricTensor
.
Examples
julia> A = rand(Tensor{2,3})
3×3 Tensor{2, 3, Float64, 9}:
0.590845 0.460085 0.200586
0.766797 0.794026 0.298614
0.566237 0.854147 0.246837
julia> dott(A)
3×3 SymmetricTensor{2, 3, Float64, 6}:
0.601011 0.878275 0.777051
0.878275 1.30763 1.18611
0.777051 1.18611 1.11112
Norm
The (2)-norm of a tensor is defined for a vector, second order tensor and fourth order tensor as
\[\|\mathbf{a}\| = \sqrt{\mathbf{a} \cdot \mathbf{a}} \Leftrightarrow \|a_i\| = \sqrt{a_i a_i},\]
\[\|\mathbf{A}\| = \sqrt{\mathbf{A} : \mathbf{A}} \Leftrightarrow \|A_{ij}\| = \sqrt{A_{ij} A_{ij}},\]
\[\|\mathsf{A}\| = \sqrt{\mathsf{A} :: \mathsf{A}} \Leftrightarrow \|A_{ijkl}\| = \sqrt{A_{ijkl} A_{ijkl}}.\]
LinearAlgebra.norm
— Functionnorm(::Vec)
norm(::SecondOrderTensor)
norm(::FourthOrderTensor)
Computes the norm of a tensor.
Examples
julia> A = rand(Tensor{2,3})
3×3 Tensor{2, 3, Float64, 9}:
0.590845 0.460085 0.200586
0.766797 0.794026 0.298614
0.566237 0.854147 0.246837
julia> norm(A)
1.7377443667834922
Trace
The trace for a second order tensor is defined as the sum of the diagonal elements. This can be written as
\[\text{tr}(\mathbf{A}) = \mathbf{I} : \mathbf{A} \Leftrightarrow \text{tr}(A_{ij}) = A_{ii}.\]
LinearAlgebra.tr
— Functiontr(::SecondOrderTensor)
Computes the trace of a second order tensor.
Examples
julia> A = rand(SymmetricTensor{2,3})
3×3 SymmetricTensor{2, 3, Float64, 6}:
0.590845 0.766797 0.566237
0.766797 0.460085 0.794026
0.566237 0.794026 0.854147
julia> tr(A)
1.9050765715072775
Determinant
Determinant for a second order tensor.
LinearAlgebra.det
— Functiondet(::SecondOrderTensor)
Computes the determinant of a second order tensor.
Examples
julia> A = rand(SymmetricTensor{2,3})
3×3 SymmetricTensor{2, 3, Float64, 6}:
0.590845 0.766797 0.566237
0.766797 0.460085 0.794026
0.566237 0.794026 0.854147
julia> det(A)
-0.1005427219925894
Inverse
Inverse of a second order tensor such that
\[\mathbf{A}^{-1} \cdot \mathbf{A} = \mathbf{I}\]
where $\mathbf{I}$ is the second order identitiy tensor.
Base.inv
— Functioninv(::SecondOrderTensor)
Computes the inverse of a second order tensor.
Examples
julia> A = rand(Tensor{2,3})
3×3 Tensor{2, 3, Float64, 9}:
0.590845 0.460085 0.200586
0.766797 0.794026 0.298614
0.566237 0.854147 0.246837
julia> inv(A)
3×3 Tensor{2, 3, Float64, 9}:
19.7146 -19.2802 7.30384
6.73809 -10.7687 7.55198
-68.541 81.4917 -38.8361
Transpose
Transpose of tensors is defined by changing the order of the tensor's "legs". The transpose of a vector/symmetric tensor is the vector/tensor itself. The transpose of a second order tensor can be written as:
\[A_{ij}^\text{T} = A_{ji}\]
and for a fourth order tensor the minor transpose can be written as
\[A_{ijkl}^\text{t} = A_{jilk}\]
and the major transpose as
\[A_{ijkl}^\text{T} = A_{klij}.\]
Base.transpose
— Functiontranspose(::Vec)
transpose(::SecondOrderTensor)
transpose(::FourthOrderTensor)
Compute the transpose of a tensor. For a fourth order tensor, the transpose is the minor transpose.
Examples
julia> A = rand(Tensor{2,2})
2×2 Tensor{2, 2, Float64, 4}:
0.590845 0.566237
0.766797 0.460085
julia> A'
2×2 Tensor{2, 2, Float64, 4}:
0.590845 0.766797
0.566237 0.460085
Tensors.minortranspose
— Functionminortranspose(::FourthOrderTensor)
Compute the minor transpose of a fourth order tensor.
Tensors.majortranspose
— Functionmajortranspose(::FourthOrderTensor)
Compute the major transpose of a fourth order tensor.
Symmetric
The symmetric part of a second order tensor is defined by:
\[\mathbf{A}^\text{sym} = \frac{1}{2}(\mathbf{A} + \mathbf{A}^\text{T}) \Leftrightarrow A_{ij}^\text{sym} = \frac{1}{2}(A_{ij} + A_{ji}),\]
The major symmetric part of a fourth order tensor is defined by
\[\mathsf{A}^\text{majsym} = \frac{1}{2}(\mathsf{A} + \mathsf{A}^\text{T}) \Leftrightarrow A_{ijkl}^\text{majsym} = \frac{1}{2}(A_{ijkl} + A_{klij}).\]
The minor symmetric part of a fourth order tensor is defined by
\[A_{ijkl}^\text{minsym} = \frac{1}{4}(A_{ijkl} + A_{ijlk} + A_{jikl} + A_{jilk}).\]
Tensors.symmetric
— Functionsymmetric(::SecondOrderTensor)
symmetric(::FourthOrderTensor)
Computes the (minor) symmetric part of a second or fourth order tensor. Return a SymmetricTensor
.
Examples
julia> A = rand(Tensor{2,2})
2×2 Tensor{2, 2, Float64, 4}:
0.590845 0.566237
0.766797 0.460085
julia> symmetric(A)
2×2 SymmetricTensor{2, 2, Float64, 3}:
0.590845 0.666517
0.666517 0.460085
Tensors.minorsymmetric
— Functionminorsymmetric(::FourthOrderTensor)
Compute the minor symmetric part of a fourth order tensor, return a SymmetricTensor{4}
.
Tensors.majorsymmetric
— Functionmajorsymmetric(::FourthOrderTensor)
Compute the major symmetric part of a fourth order tensor.
Skew symmetric
The skew symmetric part of a second order tensor is defined by
\[\mathbf{A}^\text{skw} = \frac{1}{2}(\mathbf{A} - \mathbf{A}^\text{T}) \Leftrightarrow A^\text{skw}_{ij} = \frac{1}{2}(A_{ij} - A_{ji}).\]
The skew symmetric part of a symmetric tensor is zero.
Tensors.skew
— Functionskew(::SecondOrderTensor)
Computes the skew-symmetric (anti-symmetric) part of a second order tensor, returns a Tensor{2}
.
Deviatoric tensor
The deviatoric part of a second order tensor is defined by
\[\mathbf{A}^\text{dev} = \mathbf{A} - \frac{1}{3} \mathrm{tr}[\mathbf{A}] \mathbf{I} \Leftrightarrow A_{ij}^\text{dev} = A_{ij} - \frac{1}{3}A_{kk}\delta_{ij}.\]
Tensors.dev
— Functiondev(::SecondOrderTensor)
Computes the deviatoric part of a second order tensor.
Examples
julia> A = rand(Tensor{2, 3});
julia> dev(A)
3×3 Tensor{2, 3, Float64, 9}:
0.0469421 0.460085 0.200586
0.766797 0.250123 0.298614
0.566237 0.854147 -0.297065
julia> tr(dev(A))
0.0
Volumetric tensor
The volumetric part of a second order tensor is defined by
\[\mathbf{A}^\text{vol} = \frac{1}{3} \mathrm{tr}[\mathbf{A}] \mathbf{I} \Leftrightarrow A_{ij}^\text{vol} = \frac{1}{3}A_{kk}\delta_{ij}.\]
Tensors.vol
— Functionvol(::SecondOrderTensor)
Computes the volumetric part of a second order tensor based on the additive decomposition.
Examples
julia> A = rand(SymmetricTensor{2,3})
3×3 SymmetricTensor{2, 3, Float64, 6}:
0.590845 0.766797 0.566237
0.766797 0.460085 0.794026
0.566237 0.794026 0.854147
julia> vol(A)
3×3 SymmetricTensor{2, 3, Float64, 6}:
0.635026 0.0 0.0
0.0 0.635026 0.0
0.0 0.0 0.635026
julia> vol(A) + dev(A) ≈ A
true
Cross product
The cross product between two vectors is defined as
\[\mathbf{a} = \mathbf{b} \times \mathbf{c} \Leftrightarrow a_i = \epsilon_{ijk} b_j c_k\]
LinearAlgebra.cross
— Functioncross(::Vec, ::Vec)
Computes the cross product between two Vec
vectors, returns a Vec{3}
. For dimensions 1 and 2 the Vec
's are expanded to 3D first. The infix operator ×
(written \times
) can also be used.
Examples
julia> a = rand(Vec{3})
3-element Vec{3, Float64}:
0.5908446386657102
0.7667970365022592
0.5662374165061859
julia> b = rand(Vec{3})
3-element Vec{3, Float64}:
0.4600853424625171
0.7940257103317943
0.8541465903790502
julia> a × b
3-element Vec{3, Float64}:
0.20535000738340053
-0.24415039787171888
0.11635375677388776
Eigenvalues and eigenvectors
The eigenvalues and eigenvectors of a (symmetric) second order tensor, $\mathbf{A}$ can be solved from the eigenvalue problem
\[\mathbf{A} \cdot \mathbf{v}_i = \lambda_i \mathbf{v}_i \qquad i = 1, \dots, \text{dim}\]
where $\lambda_i$ are the eigenvalues and $\mathbf{v}_i$ are the corresponding eigenvectors. For a symmetric fourth order tensor, $\mathsf{A}$ the second order eigentensors and eigenvalues can be solved from
\[\mathsf{A} : \mathbf{V}_i = \lambda_i \mathbf{V}_i \qquad i = 1, \dots, \text{dim}\]
where $\lambda_i$ are the eigenvalues and $\mathbf{V}_i$ the corresponding eigentensors.
LinearAlgebra.eigen
— Functioneigen(A::SymmetricTensor{2})
Compute the eigenvalues and eigenvectors of a symmetric second order tensor and return an Eigen
object. The eigenvalues are stored in a Vec
, sorted in ascending order. The corresponding eigenvectors are stored as the columns of a Tensor
.
Examples
julia> A = rand(SymmetricTensor{2, 2});
julia> E = eigen(A);
julia> E.values
2-element Vec{2, Float64}:
-0.1883547111127678
1.345436766284664
julia> E.vectors
2×2 Tensor{2, 2, Float64, 4}:
-0.701412 0.712756
0.712756 0.701412
eigen(A::SymmetricTensor{4})
Compute the eigenvalues and second order eigentensors of a symmetric fourth order tensor and return an FourthOrderEigen
object. The eigenvalues and eigentensors are sorted in ascending order of the eigenvalues.
LinearAlgebra.eigvals
— Functioneigvals(::SymmetricTensor)
Compute the eigenvalues of a symmetric tensor.
eigvals(::Union{Eigen,FourthOrderEigen})
Extract eigenvalues from an Eigen
or FourthOrderEigen
object, returned by eigen
.
LinearAlgebra.eigvecs
— Functioneigvecs(::SymmetricTensor)
Compute the eigenvectors of a symmetric tensor.
eigvecs(::Union{Eigen,FourthOrderEigen})
Extract eigenvectors from an Eigen
or FourthOrderEigen
object, returned by eigen
.
Tensor square root
Square root of a symmetric positive definite second order tensor $S$, defined such that
\[\sqrt{\mathbf{S}} \cdot \sqrt{\mathbf{S}} = S.\]
Base.sqrt
— Functionsqrt(S::SymmetricTensor{2})
Calculate the square root of the positive definite symmetric second order tensor S
, such that √S ⋅ √S == S
.
Examples
julia> S = rand(SymmetricTensor{2,2}); S = tdot(S)
2×2 SymmetricTensor{2, 2, Float64, 3}:
0.937075 0.887247
0.887247 0.908603
julia> sqrt(S)
2×2 SymmetricTensor{2, 2, Float64, 3}:
0.776178 0.578467
0.578467 0.757614
julia> √S ⋅ √S ≈ S
true
Rotations
Tensors.rotate
— Functionrotate(x::AbstractTensor{3}, u::Vec{3}, θ::Number)
Rotate a three dimensional tensor x
around the vector u
a total of θ
radians.
Examples
julia> x = Vec{3}((0.0, 0.0, 1.0));
julia> u = Vec{3}((0.0, 1.0, 0.0));
julia> rotate(x, u, π/2)
3-element Vec{3, Float64}:
1.0
0.0
6.123233995736766e-17
rotate(x::AbstractTensor{2}, θ::Number)
Rotate a two dimensional tensor x
θ
radians around the out-of-plane axis.
Examples
julia> x = Vec{2}((0.0, 1.0));
julia> rotate(x, π/4)
2-element Vec{2, Float64}:
-0.7071067811865475
0.7071067811865476
Tensors.rotation_tensor
— Functionrotation_tensor(θ::Number)
Return the two-dimensional rotation matrix corresponding to rotation of θ
radians around the out-of-plane axis (i.e. around (0, 0, 1)
).
rotation_tensor(ψ::Number, θ::Number, ϕ::Number)
Return the three-dimensional rotation matrix corresponding to the rotation described by the three Euler angles $ψ$, $θ$, $ϕ$.
\[R(ψ,θ,ϕ) = R_x(ψ)R_y(θ)R_z(ϕ)\]
see e.g. http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf for a complete description.
Note that the gimbal lock phenomena can occur when using this rotation tensor parametrization.
rotation_tensor(u::Vec{3}, θ::Number)
Return the three-dimensional rotation matrix corresponding to rotation of θ
radians around the vector u
.
Special operations
For computing a special dot product between two vectors $\mathbf{a}$ and $\mathbf{b}$ with a fourth order symmetric tensor $\mathbf{C}$ such that $a_k C_{ikjl} b_l$ there is dotdot(a, C, b)
. This function is useful because it is the expression for the tangent matrix in continuum mechanics when the displacements are approximated by scalar shape functions.
Tensors.dotdot
— Functiondotdot(::Vec, ::SymmetricFourthOrderTensor, ::Vec)
Computes a special dot product between two vectors and a symmetric fourth order tensor such that $a_k C_{ikjl} b_l$.
Voigt format
For some operations it is convenient to easily switch to the so called "Voigt"-format. For example when solving a local problem in a plasticity model. To simplify the conversion between tensors and Voigt format, see tovoigt
, tovoigt!
and fromvoigt
documented below. Care must be exercised when combined with differentiation, see Differentiation of Voigt format further down.
Tensors.tovoigt
— Functiontovoigt([type::Type{<:AbstractArray}, ]A::Union{SecondOrderTensor, FourthOrderTensor}; kwargs...)
Converts a tensor to "Voigt"-format.
Optional argument:
type
: determines the returned Array type. Possible types areArray
andSArray
(seeStaticArrays
).
Keyword arguments:
offdiagscale
: determines the scaling factor for the offdiagonal elements. This argument is only applicable forSymmetricTensor
s.tomandel
can also be used for the "Mandel"-format which setsoffdiagscale = √2
forSymmetricTensor
s, and is equivalent totovoigt
forTensor
s.order
: matrix of the linear indices determining the Voigt order. The default index order is[11, 22, 33, 23, 13, 12, 32, 31, 21]
, corresponding toorder = [1 6 5; 9 2 4; 8 7 3]
.
See also tovoigt!
and fromvoigt
.
julia> tovoigt(Tensor{2,3}(1:9))
9-element Vector{Int64}:
1
5
9
8
7
4
6
3
2
julia> tovoigt(SymmetricTensor{2,3}(1:6); offdiagscale = 2)
6-element Vector{Int64}:
1
4
6
10
6
4
julia> tovoigt(Tensor{4,2}(1:16))
4×4 Matrix{Int64}:
1 13 9 5
4 16 12 8
3 15 11 7
2 14 10 6
julia> tovoigt(SMatrix, Tensor{4,2}(1:16))
4×4 SMatrix{4, 4, Int64, 16} with indices SOneTo(4)×SOneTo(4):
1 13 9 5
4 16 12 8
3 15 11 7
2 14 10 6
Tensors.tovoigt!
— Functiontovoigt!(v::AbstractArray, A::Union{SecondOrderTensor, FourthOrderTensor}; kwargs...)
Converts a tensor to "Voigt"-format using the following index order: [11, 22, 33, 23, 13, 12, 32, 31, 21]
.
Keyword arguments:
offset
: offset index for where in the arrayA
the tensor should be stored. For 4th order tensors the keyword arguments areoffset_i
andoffset_j
, respectively. Defaults to0
.offdiagscale
: determines the scaling factor for the offdiagonal elements. This argument is only applicable forSymmetricTensor
s.frommandel!
can also be used for the "Mandel"-format which setsoffdiagscale = √2
forSymmetricTensor
s, and is equivalent tofromvoigt!
forTensor
s.order
: matrix of the linear indices determining the Voigt order. The default index order is[11, 22, 33, 23, 13, 12, 32, 31, 21]
.
See also tovoigt
and fromvoigt
.
julia> T = rand(Tensor{2,2})
2×2 Tensor{2, 2, Float64, 4}:
0.590845 0.566237
0.766797 0.460085
julia> x = zeros(4);
julia> tovoigt!(x, T)
4-element Vector{Float64}:
0.5908446386657102
0.4600853424625171
0.5662374165061859
0.7667970365022592
julia> x = zeros(5);
julia> tovoigt!(x, T; offset=1)
5-element Vector{Float64}:
0.0
0.5908446386657102
0.4600853424625171
0.5662374165061859
0.7667970365022592
Tensors.fromvoigt
— Functionfromvoigt(S::Type{<:AbstractTensor}, A::AbstractArray{T}; kwargs...)
Converts an array A
stored in Voigt format to a Tensor of type S
.
Keyword arguments:
offset
: offset index for where in the arrayA
the tensor starts. For 4th order tensors the keyword arguments areoffset_i
andoffset_j
, respectively. Defaults to0
.offdiagscale
: determines the scaling factor for the offdiagonal elements. This argument is only applicable forSymmetricTensor
s.frommandel
can also be used for the "Mandel"-format which setsoffdiagscale = √2
forSymmetricTensor
s, and is equivalent tofromvoigt
forTensor
s.order
: matrix of the linear indices determining the Voigt order. The default index order is[11, 22, 33, 23, 13, 12, 32, 31, 21]
, corresponding toorder = [1 6 5; 9 2 4; 8 7 3]
.
See also tovoigt
.
julia> fromvoigt(Tensor{2,3}, 1.0:1.0:9.0)
3×3 Tensor{2, 3, Float64, 9}:
1.0 6.0 5.0
9.0 2.0 4.0
8.0 7.0 3.0
Differentiation of Voigt format
Differentiating with a Voigt representation of a symmetric tensor may lead to incorrect results when converted back to tensors. The tomandel
, tomandel!
, and frommandel
versions of tovoigt
, tovoigt!
, and fromvoigt
can then be used. As illustrated by the following example, this will give the correct result. In general, however, direct differentiation of Tensor
s is faster (see Automatic Differentiation).
julia> using Tensors, ForwardDiff
julia> fun(X::SymmetricTensor{2}) = X;
julia> A = rand(SymmetricTensor{2,2});
# Differentiation of a tensor directly (correct)
julia> tovoigt(gradient(fun, A))
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 0.5
# Converting to Voigt format, perform differentiation, convert back (WRONG!)
julia> ForwardDiff.jacobian(
v -> tovoigt(fun(fromvoigt(SymmetricTensor{2,2}, v))),
tovoigt(A)
)
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
# Converting to Mandel format, perform differentiation, convert back (correct)
julia> tovoigt(
frommandel(SymmetricTensor{4,2},
ForwardDiff.jacobian(
v -> tomandel(fun(frommandel(SymmetricTensor{2,2}, v))),
tomandel(A)
)
)
)
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 0.5