Special tensors and rotations
Levi-Civita symbol, rotation tensors, predefined unit vectors and random tensors. Theory: Rotations and Euler angles.
TensND.levi_civita Function
levi_civita(T::Type{<:Number} = Sym)Builds an Array{T,3} of Levi-Civita Symbol ϵᵢⱼₖ = (i-j) (j-k) (k-i) / 2
Examples
julia> ε = levi_civita(Sym)
3×3×3 Array{Sym, 3}:
[:, :, 1] =
0 0 0
0 0 1
0 -1 0
[:, :, 2] =
0 0 -1
0 0 0
1 0 0
[:, :, 3] =
0 1 0
-1 0 0
0 0 0TensND.rotation_matrix Function
rotation_matrix(θ, ϕ, ψ = 0)The 3×3 rotation matrix of the Euler angles θ, ϕ, ψ (ZYZ: θ the inclination from ϕ the azimuth, ψ the spin about the rotated axis). Its third column is the unit vector of inclination θ and azimuth ϕ. With a single angle, rotation_matrix(θ) is the 2D rotation.
Examples
julia> cθ, cϕ, cψ, sθ, sϕ, sψ = symbols("cθ cϕ cψ sθ sϕ sψ", real = true) ;
julia> d = Dict(cos(θ) => cθ, cos(ϕ) => cϕ, cos(ψ) => cψ, sin(θ) => sθ, sin(ϕ) => sϕ, sin(ψ) => sψ) ;
julia> subs.(rotation_matrix(θ, ϕ, ψ),d...)
3×3 StaticArrays.SMatrix{3, 3, Sym, 9} with indices SOneTo(3)×SOneTo(3):
cθ⋅cψ⋅cϕ - sψ⋅sϕ -cθ⋅cϕ⋅sψ - cψ⋅sϕ cϕ⋅sθ
cθ⋅cψ⋅sϕ + cϕ⋅sψ -cθ⋅sψ⋅sϕ + cψ⋅cϕ sθ⋅sϕ
-cψ⋅sθ sθ⋅sψ cθrotation_matrix(θ)The 2D rotation matrix of angle θ, as a Tensor{2, 2}.
Examples
julia> rotation_matrix(θ)
2×2 Tensor{2, 2, Sym, 4}:
cos(θ) -sin(θ)
sin(θ) cos(θ)TensND.rotation_tensor4 Function
rotation_tensor4(θ, ϕ = 0, ψ = 0)The fourth-order tensor R = rotation_matrix(θ, ϕ, ψ); its Kelvin-Mandel matrix is the 6×6 rotation mandel_rotation(θ, ϕ, ψ).
Examples
julia> cθ, cϕ, cψ, sθ, sϕ, sψ = symbols("cθ cϕ cψ sθ sϕ sψ", real = true) ;
julia> d = Dict(cos(θ) => cθ, cos(ϕ) => cϕ, cos(ψ) => cψ, sin(θ) => sθ, sin(ϕ) => sϕ, sin(ψ) => sψ) ;
julia> R = Tens(subs.(rotation_matrix(θ, ϕ, ψ),d...))
Tens.TensCanonical{2, 3, Sym, Tensor{2, 3, Sym, 9}}
# data: 3×3 Tensor{2, 3, Sym, 9}:
cθ⋅cψ⋅cϕ - sψ⋅sϕ -cθ⋅cϕ⋅sψ - cψ⋅sϕ cϕ⋅sθ
cθ⋅cψ⋅sϕ + cϕ⋅sψ -cθ⋅sψ⋅sϕ + cψ⋅cϕ sθ⋅sϕ
-cψ⋅sθ sθ⋅sψ cθ
# var: (:cont, :cont)
# basis: 3×3 Tens.LazyIdentity{3, Sym}:
1 0 0
0 1 0
0 0 1
julia> RR = R ⊠ˢ R
Tens.TensCanonical{4, 3, Sym, SymmetricTensor{4, 3, Sym, 36}}
# data: 6×6 Matrix{Sym}:
(cθ*cψ*cϕ - sψ*sϕ)^2 (-cθ*cϕ*sψ - cψ*sϕ)^2 cϕ^2*sθ^2 √2⋅cϕ⋅sθ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) √2⋅cϕ⋅sθ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) √2⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ)
(cθ*cψ*sϕ + cϕ*sψ)^2 (-cθ*sψ*sϕ + cψ*cϕ)^2 sθ^2*sϕ^2 √2⋅sθ⋅sϕ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) √2⋅sθ⋅sϕ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ)⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ)
cψ^2*sθ^2 sθ^2*sψ^2 cθ^2 √2⋅cθ⋅sθ⋅sψ -√2⋅cθ⋅cψ⋅sθ -sqrt(2)*cψ*sθ^2*sψ
-√2⋅cψ⋅sθ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅sθ⋅sψ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) √2⋅cθ⋅sθ⋅sϕ cθ*(-cθ*sψ*sϕ + cψ*cϕ) + sθ^2*sψ*sϕ cθ*(cθ*cψ*sϕ + cϕ*sψ) - cψ*sθ^2*sϕ -cψ⋅sθ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) + sθ⋅sψ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ)
-√2⋅cψ⋅sθ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) √2⋅sθ⋅sψ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) √2⋅cθ⋅cϕ⋅sθ cθ*(-cθ*cϕ*sψ - cψ*sϕ) + cϕ*sθ^2*sψ cθ*(cθ*cψ*cϕ - sψ*sϕ) - cψ*cϕ*sθ^2 -cψ⋅sθ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) + sθ⋅sψ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)
√2⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ)⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) sqrt(2)*cϕ*sθ^2*sϕ cϕ⋅sθ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) + sθ⋅sϕ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) cϕ⋅sθ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) + sθ⋅sϕ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) (cθ*cψ*cϕ - sψ*sϕ)*(-cθ*sψ*sϕ + cψ*cϕ) + (cθ*cψ*sϕ + cϕ*sψ)*(-cθ*cϕ*sψ - cψ*sϕ)
# var: (:cont, :cont, :cont, :cont)
# basis: 3×3 Tens.LazyIdentity{3, Sym}:
1 0 0
0 1 0
0 0 1
julia> R6 = from_mandel(subs.(mandel(rotation_tensor4(θ, ϕ, ψ)),d...))
Tens.TensCanonical{4, 3, Sym, SymmetricTensor{4, 3, Sym, 36}}
# data: 6×6 Matrix{Sym}:
(cθ*cψ*cϕ - sψ*sϕ)^2 (-cθ*cϕ*sψ - cψ*sϕ)^2 cϕ^2*sθ^2 √2⋅cϕ⋅sθ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) √2⋅cϕ⋅sθ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) √2⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ)
(cθ*cψ*sϕ + cϕ*sψ)^2 (-cθ*sψ*sϕ + cψ*cϕ)^2 sθ^2*sϕ^2 √2⋅sθ⋅sϕ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) √2⋅sθ⋅sϕ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ)⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ)
cψ^2*sθ^2 sθ^2*sψ^2 cθ^2 √2⋅cθ⋅sθ⋅sψ -√2⋅cθ⋅cψ⋅sθ -sqrt(2)*cψ*sθ^2*sψ
-√2⋅cψ⋅sθ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅sθ⋅sψ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) √2⋅cθ⋅sθ⋅sϕ cθ*(-cθ*sψ*sϕ + cψ*cϕ) + sθ^2*sψ*sϕ cθ*(cθ*cψ*sϕ + cϕ*sψ) - cψ*sθ^2*sϕ -cψ⋅sθ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) + sθ⋅sψ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ)
-√2⋅cψ⋅sθ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) √2⋅sθ⋅sψ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) √2⋅cθ⋅cϕ⋅sθ cθ*(-cθ*cϕ*sψ - cψ*sϕ) + cϕ*sθ^2*sψ cθ*(cθ*cψ*cϕ - sψ*sϕ) - cψ*cϕ*sθ^2 -cψ⋅sθ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) + sθ⋅sψ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)
√2⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ)⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) √2⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ)⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) sqrt(2)*cϕ*sθ^2*sϕcϕ⋅sθ⋅(-cθ⋅sψ⋅sϕ + cψ⋅cϕ) + sθ⋅sϕ⋅(-cθ⋅cϕ⋅sψ - cψ⋅sϕ) cϕ⋅sθ⋅(cθ⋅cψ⋅sϕ + cϕ⋅sψ) + sθ⋅sϕ⋅(cθ⋅cψ⋅cϕ - sψ⋅sϕ) (cθ*cψ*cϕ - sψ*sϕ)*(-cθ*sψ*sϕ + cψ*cϕ) + (cθ*cψ*sϕ + cϕ*sψ)*(-cθ*cϕ*sψ - cψ*sϕ)
# var: (:cont, :cont, :cont, :cont)
# basis: 3×3 Tens.LazyIdentity{3, Sym}:
1 0 0
0 1 0
0 0 1
julia> R6 == RR
trueTensND.𝐞 Function
𝐞(i::Integer, dim::Int = 3, T::Type{<:Number} = Sym)Vector of the canonical basis
Examples
julia> 𝐞(1)
Tens{1, 3, Sym, Sym, Vec{3, Sym}, CanonicalBasis{3, Sym}}
# data: 3-element Vec{3, Sym}:
1
0
0
# var: (:cont,)
# basis: 3×3 Tensor{2, 3, Sym, 9}:
1 0 0
0 1 0
0 0 1TensND.𝐞ᵖ Function
𝐞ᵖ(i::Integer, θ::T = zero(Sym); canonical = false)Vector of the polar basis
Examples
julia> θ = symbols("θ", real = true) ;
julia> 𝐞ᵖ(1, θ)
Tens{1, 2, Sym, Sym, Vec{2, Sym}, RotatedBasis{2, Sym}}
# data: 2-element Vec{2, Sym}:
1
0
# var: (:cont,)
# basis: 2×2 Tensor{2, 2, Sym, 4}:
cos(θ) -sin(θ)
sin(θ) cos(θ)TensND.𝐞ᶜ Function
𝐞ᶜ(i::Integer, θ::T = zero(Sym); canonical = false)Vector of the cylindrical basis
Examples
julia> θ = symbols("θ", real = true) ;
julia> 𝐞ᶜ(1, θ)
Tens{1, 3, Sym, Sym, Vec{3, Sym}, RotatedBasis{3, Sym}}
# data: 3-element Vec{3, Sym}:
1
0
0
# var: (:cont,)
# basis: 3×3 Tensor{2, 3, Sym, 9}:
cos(θ) -sin(θ) 0
sin(θ) cos(θ) 0
0 0 1TensND.𝐞ˢ Function
𝐞ˢ(i::Integer, θ::T = zero(Sym), ϕ::T = zero(Sym), ψ::T = zero(Sym); canonical = false)Vector of the basis rotated with the 3 Euler angles θ, ϕ, ψ (spherical if ψ=0)
Examples
julia> θ, ϕ, ψ = symbols("θ, ϕ, ψ", real = true) ;
Tens{1, 3, Sym, Sym, Vec{3, Sym}, RotatedBasis{3, Sym}}
# data: 3-element Vec{3, Sym}:
1
0
0
# var: (:cont,)
# basis: 3×3 Tensor{2, 3, Sym, 9}:
-sin(ψ)⋅sin(ϕ) + cos(θ)⋅cos(ψ)⋅cos(ϕ) -sin(ψ)⋅cos(θ)⋅cos(ϕ) - sin(ϕ)⋅cos(ψ) sin(θ)⋅cos(ϕ)
sin(ψ)⋅cos(ϕ) + sin(ϕ)⋅cos(θ)⋅cos(ψ) -sin(ψ)⋅sin(ϕ)⋅cos(θ) + cos(ψ)⋅cos(ϕ) sin(θ)⋅sin(ϕ)
-sin(θ)⋅cos(ψ) sin(θ)⋅sin(ψ) cos(θ)Random tensors and orientations
Manual: Random tensors. Theory: Uniform random rotations.
Base.rand Method
rand([rng], class; definite = false, ...) -> AbstractTens
rand([rng], class, dims...) -> ArrayA tensor of class with random coefficients and, for a class with a direction, a random orientation. class is the type of the tensor, given either by its class with the default shape and Float64 coefficients, or in full for another shape or element type:
class | returns | direction (keyword) |
|---|---|---|
TensISO{4, dim}, TensISO{2, dim} | isotropic | none |
TensTI{4} (N = 5), TensTI{4, T, N} (N = 5, 6, 8) | transversely isotropic | axis = random_axis(rng, T), or frame |
TensTI{2} (N = 2), TensTI{2, T, N} (N = 2, 3) | transversely isotropic | axis = random_axis(rng, T), or frame |
TensOrtho{4} (N = 9), TensOrtho{4, T, N} (N = 9, 12) | orthotropic | frame = random_basis(rng, T) |
TensOrtho{2}, TensOrtho{2, T} | orthotropic | frame = random_basis(rng, T) |
TensCubic, TensCubic{T} | cubic | frame = random_basis(rng, T) |
Tens{order, dim}, Tens{order, dim, T} (order = 2, 4) | generic | none: its law is invariant |
Passing axis or frame fixes the direction and leaves only the coefficients random; a transversely isotropic tensor takes either, the axis being the third vector of the frame. Without a generator rng, Random.default_rng() is used; rand(class, n) draws an array of n tensors of the default law, as rand does for numbers; with keywords, an array is a comprehension, [rand(rng, class; definite = true) for _ in 1:n]. definite = true draws a positive definite tensor, for the shapes with the major symmetry (the default ones); the others refuse it. A generic tensor takes symmetry: Val(:major) (the default, minor and major symmetries, the class of elastic moduli), Val(:minor) or Val(:none) at order 4, Val(:symmetric) (the default) or Val(:none) at order 2.
The laws. The Kelvin–Mandel matrix of the tensor in its own frame has the block structure of its class. Each symmetric block is drawn from the Gaussian orthogonal ensemble, or, positive definite, with Haar eigenvectors and log-normal eigenvalues; each block without symmetry has independent standard normal entries; a scalar block is standard normal, or log-normal. Each law is invariant under the orthogonal changes of basis of its block, so that a generic tensor needs no random frame, its law being already invariant under rotations. See Random tensors.
Examples
julia> using Random; rng = Xoshiro(1);
julia> ℂ = rand(rng, TensCubic; definite = true); # a cubic crystal, random cube
julia> ℂ isa TensCubic && minimum(eigvals(Symmetric(Matrix(mandel(ℂ))))) > 0
true
julia> rand(rng, TensTI{4}; axis = (0.0, 0.0, 1.0)) isa TensTI{4, Float64, 5}
trueTensND.random_rotation Function
random_rotation([rng], [T = Float64]) -> SMatrix{3, 3, T}A rotation drawn from the Haar measure of SO(3): the uniform law on the rotations, which no orientation favors. It is the rotation of a unit quaternion drawn uniformly on the unit sphere of ℝ⁴, the normalization of four independent standard normal numbers (see Random rotations).
Drawing the three Euler angles uniformly does not give this law: the axis e₃ would then fall near the poles as often as near the equator.
See also random_axis, random_basis, rand.
TensND.random_axis Function
random_axis([rng], [T = Float64]) -> NTuple{3, T}A unit vector drawn uniformly on the unit sphere: three independent standard normal numbers, normalized. It is the axis R⋅e₃ of a random_rotation R, and the law of the axis of a random transversely isotropic tensor.
TensND.random_basis Function
random_basis([rng], [T = Float64]) -> RotatedBasis{3, T}The orthonormal basis of the columns of a random_rotation: a frame of uniformly random orientation, the law of the frame of a random orthotropic or cubic tensor.