pub struct Tensor2 { /* private fields */ }Expand description
Implements a second-order tensor, symmetric or not
Internally, the components are converted to the Mandel basis as follows.
General:
┌ ┐
00 │ T00 │ 0
11 │ T11 │ 1
┌ ┐ 22 │ T22 │ 2
│ T00 T01 T02 │ 01 │ (T01+T10) / √2 │ 3
│ T10 T11 T12 │ => 12 │ (T12+T21) / √2 │ 4
│ T20 T21 T22 │ 02 │ (T02+T20) / √2 │ 5
└ ┘ 10 │ (T01-T10) / √2 │ 6
21 │ (T12-T21) / √2 │ 7
20 │ (T02-T20) / √2 │ 8
└ ┘Symmetric 3D:
┌ ┐
┌ ┐ 00 │ T00 │ 0
│ T00 T01 T02 │ 11 │ T11 │ 1
│ T01 T11 T12 │ => 22 │ T22 │ 2
│ T02 T12 T22 │ 01 │ T01 * √2 │ 3
└ ┘ 12 │ T12 * √2 │ 4
02 │ T02 * √2 │ 5
└ ┘Symmetric 2D:
┌ ┐ ┌ ┐
│ T00 T01 │ 00 │ T00 │ 0
│ T01 T11 │ => 11 │ T11 │ 1
│ T22 │ 22 │ T22 │ 2
└ ┘ 01 │ T01 * √2 │ 3
└ ┘Implementations§
Source§impl Tensor2
impl Tensor2
Sourcepub fn new(mandel: Mandel) -> Self
pub fn new(mandel: Mandel) -> Self
Creates a new (zeroed) Tensor2
§Input
mandel– the Mandel representation
§Examples
use russell_tensor::{Mandel, StrError, Tensor2};
fn main() {
let a = Tensor2::new(Mandel::General);
assert_eq!(a.vector().as_data(), &[0.0,0.0,0.0, 0.0,0.0,0.0, 0.0,0.0,0.0]);
let b = Tensor2::new(Mandel::Symmetric);
assert_eq!(b.vector().as_data(), &[0.0,0.0,0.0, 0.0,0.0,0.0]);
let c = Tensor2::new(Mandel::Symmetric2D);
assert_eq!(c.vector().as_data(), &[0.0,0.0,0.0, 0.0]);
}Sourcepub fn new_sym_ndim(space_ndim: usize) -> Self
pub fn new_sym_ndim(space_ndim: usize) -> Self
Allocates a symmetric Tensor2 given the space dimension
Note: space_ndim must be 2 or 3 (only 2 is checked, otherwise 3 is assumed)
Sourcepub fn new_from_octahedral(
distance: f64,
radius: f64,
lode: f64,
two_dim: bool,
) -> Result<Self, StrError>
pub fn new_from_octahedral( distance: f64, radius: f64, lode: f64, two_dim: bool, ) -> Result<Self, StrError>
Allocates a diagonal Tensor2 from octahedral components
§Input
distance– distance from the octahedral plane to the origin:d = (λ1 + λ2 + λ3) / √3radius– radius on the octahedral plane:r = ‖s‖lode– Lode invariant:l = cos(3θ) = (3 √3 J3)/(2 pow(J2,1.5))Note: The Lode invariant must be in-1 ≤ lode ≤ 1two_dim– 2D instead of 3D?
The octahedral components and the invariants are related as follows:
σm = d / √3 → d = σm √3
σd = r √3/√2 → r = σd √2/√3 = √2 √J2
εv = d √3 → d = εv / √3
εd = r √2/√3 → r = εd √3/√2In matrix form, the diagonal components of the tensor are the principal values (λ1, λ2, λ3):
┌ ┐
│ λ1 0 0 │
│ 0 λ2 0 │
│ 0 0 λ3 │
└ ┘Sourcepub fn new_from_octahedral_alpha(
distance: f64,
radius: f64,
alpha: f64,
two_dim: bool,
) -> Result<Self, StrError>
pub fn new_from_octahedral_alpha( distance: f64, radius: f64, alpha: f64, two_dim: bool, ) -> Result<Self, StrError>
Allocates a diagonal Tensor2 from octahedral components (using alpha angle)
§Input
distance– distance from the octahedral plane to the origin:d = (λ1 + λ2 + λ3) / √3radius– radius on the octahedral plane:r = ‖s‖alpha– alpha angle in radians from -π to πtwo_dim– 2D instead of 3D?
The octahedral components and the invariants are related as follows:
σm = d / √3 → d = σm √3
σd = r √3/√2 → r = σd √2/√3 = √2 √J2
εv = d √3 → d = εv / √3
εd = r √2/√3 → r = εd √3/√2In matrix form, the diagonal components of the tensor are the principal values (λ1, λ2, λ3):
┌ ┐
│ λ1 0 0 │
│ 0 λ2 0 │
│ 0 0 λ3 │
└ ┘Sourcepub fn vector_mut(&mut self) -> &mut Vector
pub fn vector_mut(&mut self) -> &mut Vector
Returns a mutable access to the underlying Mandel vector
Sourcepub fn set_matrix(&mut self, tt: &dyn AsMatrix3x3) -> Result<(), StrError>
pub fn set_matrix(&mut self, tt: &dyn AsMatrix3x3) -> Result<(), StrError>
Sets the Tensor2 with standard components given in matrix form
§Input
tt– the standard (not Mandel) Tij components given with respect to an orthonormal Cartesian basis
§Notes
- In all cases, even in 2D, the input matrix must be 3×3
- If symmetric, the off-diagonal components must equal each other
- If 2D,
data[1][2]anddata[0][2]must be equal to zero
§Examples
use russell_tensor::{Mandel, StrError, Tensor2, SQRT_2};
fn main() -> Result<(), StrError> {
// general
let mut a = Tensor2::new(Mandel::General);
a.set_matrix(&[
[1.0, SQRT_2 * 2.0, SQRT_2 * 3.0],
[SQRT_2 * 4.0, 5.0, SQRT_2 * 6.0],
[SQRT_2 * 7.0, SQRT_2 * 8.0, 9.0],
])?;
assert_eq!(
format!("{:.1}", a.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 5.0 │\n\
│ 9.0 │\n\
│ 6.0 │\n\
│ 14.0 │\n\
│ 10.0 │\n\
│ -2.0 │\n\
│ -2.0 │\n\
│ -4.0 │\n\
└ ┘"
);
// symmetric-3D
let mut b = Tensor2::new(Mandel::Symmetric);
b.set_matrix(&[
[1.0, 4.0 / SQRT_2, 6.0 / SQRT_2],
[4.0 / SQRT_2, 2.0, 5.0 / SQRT_2],
[6.0 / SQRT_2, 5.0 / SQRT_2, 3.0],
])?;
assert_eq!(
format!("{:.1}", b.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 2.0 │\n\
│ 3.0 │\n\
│ 4.0 │\n\
│ 5.0 │\n\
│ 6.0 │\n\
└ ┘"
);
// symmetric-2D
let mut c = Tensor2::new(Mandel::Symmetric2D);
c.set_matrix(&[
[ 1.0, 4.0/SQRT_2, 0.0],
[4.0/SQRT_2, 2.0, 0.0],
[ 0.0, 0.0, 3.0],
])?;
assert_eq!(
format!("{:.1}", c.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 2.0 │\n\
│ 3.0 │\n\
│ 4.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn from_matrix(
tt: &dyn AsMatrix3x3,
mandel: Mandel,
) -> Result<Self, StrError>
pub fn from_matrix( tt: &dyn AsMatrix3x3, mandel: Mandel, ) -> Result<Self, StrError>
Creates a new Tensor2 constructed from a 3x3 matrix
§Input
tt– the standard (not Mandel) Tij components with respect to an orthonormal Cartesian basismandel– the Mandel representation
§Notes
- In all cases, even in 2D, the input matrix must be 3×3
- If symmetric, the off-diagonal components must equal each other
- If 2D,
data[1][2]anddata[0][2]must be equal to zero
§Panics
A panic will occur if the matrix is not 3x3.
§Examples
use russell_tensor::{Mandel, StrError, Tensor2, SQRT_2};
fn main() -> Result<(), StrError> {
// general
let a = Tensor2::from_matrix(
&[
[1.0, SQRT_2 * 2.0, SQRT_2 * 3.0],
[SQRT_2 * 4.0, 5.0, SQRT_2 * 6.0],
[SQRT_2 * 7.0, SQRT_2 * 8.0, 9.0],
],
Mandel::General,
)?;
assert_eq!(
format!("{:.1}", a.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 5.0 │\n\
│ 9.0 │\n\
│ 6.0 │\n\
│ 14.0 │\n\
│ 10.0 │\n\
│ -2.0 │\n\
│ -2.0 │\n\
│ -4.0 │\n\
└ ┘"
);
// symmetric-3D
let b = Tensor2::from_matrix(
&[
[1.0, 4.0 / SQRT_2, 6.0 / SQRT_2],
[4.0 / SQRT_2, 2.0, 5.0 / SQRT_2],
[6.0 / SQRT_2, 5.0 / SQRT_2, 3.0],
],
Mandel::Symmetric,
)?;
assert_eq!(
format!("{:.1}", b.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 2.0 │\n\
│ 3.0 │\n\
│ 4.0 │\n\
│ 5.0 │\n\
│ 6.0 │\n\
└ ┘"
);
// symmetric-2D
let c = Tensor2::from_matrix(
&[
[ 1.0, 4.0/SQRT_2, 0.0],
[4.0/SQRT_2, 2.0, 0.0],
[ 0.0, 0.0, 3.0],
],
Mandel::Symmetric2D,
)?;
assert_eq!(
format!("{:.1}", c.vector()),
"┌ ┐\n\
│ 1.0 │\n\
│ 2.0 │\n\
│ 3.0 │\n\
│ 4.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn identity(mandel: Mandel) -> Self
pub fn identity(mandel: Mandel) -> Self
Returns a new identity tensor
§Examples
use russell_tensor::{Mandel, Tensor2};
let ii = Tensor2::identity(Mandel::General);
assert_eq!(
format!("{}", ii.vector()),
"┌ ┐\n\
│ 1 │\n\
│ 1 │\n\
│ 1 │\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
└ ┘"
);Sourcepub fn get(&self, i: usize, j: usize) -> f64
pub fn get(&self, i: usize, j: usize) -> f64
Returns the standard (i,j) component
Note: Returns the standard component; not Mandel.
§Input
i– the first index in(0, 1, 2)j– the first index in(0, 1, 2)
§Panics
A panic will occur if the indices are out of range.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 2.0, 0.0],
[3.0, -1.0, 5.0],
[0.0, 4.0, 1.0],
], Mandel::General)?;
approx_eq(a.get(1,2), 5.0, 1e-15);
Ok(())
}Sourcepub fn as_matrix(&self) -> Matrix
pub fn as_matrix(&self) -> Matrix
Returns a 3x3 matrix with the standard components
Note: The matrix will have the standard components (not Mandel) and 3x3 dimension.
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 1.0, 0.0],
[1.0, -1.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric2D)?;
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 1.0 1.0 0.0 │\n\
│ 1.0 -1.0 0.0 │\n\
│ 0.0 0.0 1.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn to_matrix(&self, mat: &mut Matrix)
pub fn to_matrix(&self, mat: &mut Matrix)
Converts this tensor to a 3x3 matrix with the standard components
§Input
mat– the resulting 3x3 matrix
§Panics
A panic will occur if the matrix is not 3x3
§Examples
use russell_lab::Matrix;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 1.0, 0.0],
[1.0, -1.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric2D)?;
let mut mat = Matrix::new(3, 3);
a.to_matrix(&mut mat);
assert_eq!(
format!("{:.1}", mat),
"┌ ┐\n\
│ 1.0 1.0 0.0 │\n\
│ 1.0 -1.0 0.0 │\n\
│ 0.0 0.0 1.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn as_matrix_2d(&self) -> (f64, Matrix)
pub fn as_matrix_2d(&self) -> (f64, Matrix)
Returns a 2x2 matrix with the standard components
§Notes
- The matrix will have the standard components (not Mandel) and 2x2 dimension
- This function returns the third diagonal component T22 and the 2x2 matrix
§Panics
A panic will occur if the tensor is not Mandel::Symmetric2D
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let tt = Tensor2::from_matrix(&[
[1.0, 2.0, 0.0],
[2.0, 3.0, 0.0],
[0.0, 0.0, 4.0],
], Mandel::Symmetric2D)?;
let (t22, res) = tt.as_matrix_2d();
assert_eq!(t22, 4.0);
assert_eq!(
format!("{:.1}", res),
"┌ ┐\n\
│ 1.0 2.0 │\n\
│ 2.0 3.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn as_general(&self) -> Tensor2
pub fn as_general(&self) -> Tensor2
Returns a general Tensor2 regardless of Mandel type
§Output
Returns a Mandel::General tensor.
§Examples
use russell_tensor::{Mandel, Tensor2, StrError, SQRT_2};
fn main() -> Result<(), StrError> {
let tt = Tensor2::from_matrix(&[
[1.0, 2.0/SQRT_2, 0.0],
[2.0/SQRT_2, 3.0, 0.0],
[0.0, 0.0, 4.0],
], Mandel::Symmetric2D)?;
assert_eq!(
format!("{:.2}", tt.vector()),
"┌ ┐\n\
│ 1.00 │\n\
│ 3.00 │\n\
│ 4.00 │\n\
│ 2.00 │\n\
└ ┘"
);
let tt_gen = tt.as_general();
assert_eq!(
format!("{:.2}", tt_gen.vector()),
"┌ ┐\n\
│ 1.00 │\n\
│ 3.00 │\n\
│ 4.00 │\n\
│ 2.00 │\n\
│ 0.00 │\n\
│ 0.00 │\n\
│ 0.00 │\n\
│ 0.00 │\n\
│ 0.00 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn sym2d_as_symmetric(&self) -> Tensor2
pub fn sym2d_as_symmetric(&self) -> Tensor2
Returns a Symmetric tensor from a Symmetric2D tensor
§Output
Returns a Mandel::Symmetric tensor if this tensor is Mandel::Symmetric2D.
§Panics
A panic will occur if this tensor is not Mandel::Symmetric2D.
§Examples
use russell_tensor::{Mandel, Tensor2, StrError, SQRT_2};
fn main() -> Result<(), StrError> {
let tt = Tensor2::from_matrix(&[
[1.0, 2.0/SQRT_2, 0.0],
[2.0/SQRT_2, 3.0, 0.0],
[0.0, 0.0, 4.0],
], Mandel::Symmetric2D)?;
assert_eq!(
format!("{:.2}", tt.vector()),
"┌ ┐\n\
│ 1.00 │\n\
│ 3.00 │\n\
│ 4.00 │\n\
│ 2.00 │\n\
└ ┘"
);
let tt_sym = tt.sym2d_as_symmetric();
assert_eq!(
format!("{:.2}", tt_sym.vector()),
"┌ ┐\n\
│ 1.00 │\n\
│ 3.00 │\n\
│ 4.00 │\n\
│ 2.00 │\n\
│ 0.00 │\n\
│ 0.00 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn sym_set(&mut self, i: usize, j: usize, value: f64)
pub fn sym_set(&mut self, i: usize, j: usize, value: f64)
Sets the (i,j) component of a symmetric Tensor2
σᵢⱼ = value§Notes
- Only the diagonal and upper-diagonal components need to be set.
- The tensor must be symmetric and (i,j) must correspond to the possible combination due to the space dimension, otherwise a panic may occur.
§Panics
- A panic will occur if the tensor is Mandel::General
- A panic will occur if the indices are out of range
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() {
let mut a = Tensor2::new(Mandel::Symmetric2D);
a.sym_set(0, 0, 1.0);
a.sym_set(1, 1, 2.0);
a.sym_set(2, 2, 3.0);
a.sym_set(0, 1, 4.0);
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 1.0 4.0 0.0 │\n\
│ 4.0 2.0 0.0 │\n\
│ 0.0 0.0 3.0 │\n\
└ ┘"
);
let mut b = Tensor2::new(Mandel::Symmetric);
b.sym_set(0, 0, 1.0);
b.sym_set(1, 1, 2.0);
b.sym_set(2, 2, 3.0);
b.sym_set(0, 1, 4.0);
b.sym_set(1, 0, 4.0);
b.sym_set(2, 0, 5.0);
assert_eq!(
format!("{:.1}", b.as_matrix()),
"┌ ┐\n\
│ 1.0 4.0 5.0 │\n\
│ 4.0 2.0 0.0 │\n\
│ 5.0 0.0 3.0 │\n\
└ ┘"
);
}Sourcepub fn sym_add(&mut self, i: usize, j: usize, alpha: f64, value: f64)
pub fn sym_add(&mut self, i: usize, j: usize, alpha: f64, value: f64)
Updates the (i,j) component of a symmetric Tensor2
σᵢⱼ += α value§Notes
- Only the diagonal and upper-diagonal components need to be handled.
- The tensor must be symmetric and (i,j) must correspond to the possible combination due to the space dimension, otherwise a panic may occur.
§Panics
- A panic will occur if the indices are out of range
- A panic will occur if the tensor is Mandel::General
- A panic will occur if
i > j(lower-diagonal)
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let mut a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[2.0, 5.0, 6.0],
[3.0, 6.0, 9.0],
], Mandel::Symmetric)?;
a.sym_add(0, 1, 2.0, 10.0);
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 1.0 22.0 3.0 │\n\
│ 22.0 5.0 6.0 │\n\
│ 3.0 6.0 9.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn set_mandel_vector(&mut self, alpha: f64, other: &[f64])
pub fn set_mandel_vector(&mut self, alpha: f64, other: &[f64])
Sets this tensor equal to another tensor (given as a Mandel vector)
self := α other§Panics
A panic will occur if the other tensor has an incorrect dimension.
§Examples
use russell_lab::Vector;
use russell_tensor::{Mandel, Tensor2, StrError, SQRT_2};
fn main() -> Result<(), StrError> {
let mut a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
let v_mandel = &Vector::from(&[
1.0,
5.0,
9.0,
6.0 / SQRT_2,
14.0 / SQRT_2,
10.0 / SQRT_2,
-2.0 / SQRT_2,
-2.0 / SQRT_2,
-4.0 / SQRT_2,
]);
a.set_mandel_vector(2.0, v_mandel.as_data());
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 2.0 4.0 6.0 │\n\
│ 8.0 10.0 12.0 │\n\
│ 14.0 16.0 18.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn set_tensor(&mut self, alpha: f64, other: &Tensor2)
pub fn set_tensor(&mut self, alpha: f64, other: &Tensor2)
Sets this tensor equal to another tensor
self := α other§Panics
A panic will occur if the tensors have different Mandel.
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let mut a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
let b = Tensor2::from_matrix(&[
[10.0, 20.0, 30.0],
[40.0, 50.0, 60.0],
[70.0, 80.0, 90.0],
], Mandel::General)?;
a.set_tensor(2.0, &b);
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 20.0 40.0 60.0 │\n\
│ 80.0 100.0 120.0 │\n\
│ 140.0 160.0 180.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn update(&mut self, alpha: f64, other: &Tensor2)
pub fn update(&mut self, alpha: f64, other: &Tensor2)
Adds another tensor to this one
self += α other§Panics
A panic will occur if the tensors have different Mandel.
§Examples
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let mut a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
let b = Tensor2::from_matrix(&[
[10.0, 20.0, 30.0],
[40.0, 50.0, 60.0],
[70.0, 80.0, 90.0],
], Mandel::General)?;
a.update(2.0, &b);
assert_eq!(
format!("{:.1}", a.as_matrix()),
"┌ ┐\n\
│ 21.0 42.0 63.0 │\n\
│ 84.0 105.0 126.0 │\n\
│ 147.0 168.0 189.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn determinant(&self) -> f64
pub fn determinant(&self) -> f64
Calculates the determinant
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
approx_eq(a.determinant(), 0.0, 1e-13);
Ok(())
}Sourcepub fn transpose(&self, at: &mut Tensor2)
pub fn transpose(&self, at: &mut Tensor2)
Returns the transpose tensor
Aᵀ = transpose(A)
[Aᵀ]ᵢⱼ = [A]ⱼᵢ§Output
at– a Tensor2 to hold the transpose tensor; with the same Mandel as this tensor
§Panics
A panic will occur if at has a different Mandel.
§Examples
use russell_lab::vec_approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.1, 1.2, 1.3],
[2.1, 2.2, 2.3],
[3.1, 3.2, 3.3],
], Mandel::General)?;
let mut at = Tensor2::new(Mandel::General);
a.transpose(&mut at);
let at_correct = Tensor2::from_matrix(&[
[1.1, 2.1, 3.1],
[1.2, 2.2, 3.2],
[1.3, 2.3, 3.3],
], Mandel::General)?;
vec_approx_eq(at.vector(), at_correct.vector(), 1e-15);
Ok(())
}Sourcepub fn inverse(&self, ai: &mut Tensor2, tolerance: f64) -> Option<f64>
pub fn inverse(&self, ai: &mut Tensor2, tolerance: f64) -> Option<f64>
Calculates the inverse tensor
A⁻¹ = inverse(A)
A · A⁻¹ = I§Output
ai– a Tensor2 to hold the inverse tensor; with the same Mandel as this tensortolerance– a tolerance for the determinant such that the inverse is computed only if |det| > tolerance
§Output
- If the determinant is zero, the inverse is not computed and returns
None - Otherwise, the inverse is computed and returns the determinant
§Panics
A panic will occur if ai has a different Mandel.
§Examples
use russell_lab::{approx_eq, mat_approx_eq, mat_mat_mul, Matrix};
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[6.0, 1.0, 2.0],
[3.0, 12.0, 4.0],
[5.0, 6.0, 15.0],
], Mandel::General)?;
let mut ai = Tensor2::new(Mandel::General);
if let Some(det) = a.inverse(&mut ai, 1e-10) {
assert_eq!(det, 827.0);
} else {
panic!("determinant is zero");
}
let a_mat = a.as_matrix();
let ai_mat = ai.as_matrix();
let mut a_times_ai = Matrix::new(3, 3);
mat_mat_mul(&mut a_times_ai, 1.0, &a_mat, &ai_mat, 0.0)?;
let ii = Matrix::diagonal(&[1.0, 1.0, 1.0]);
mat_approx_eq(&a_times_ai, &ii, 1e-15);
Ok(())
}Sourcepub fn squared(&self, a2: &mut Tensor2)
pub fn squared(&self, a2: &mut Tensor2)
Calculates the squared tensor
A² = A · A§Output
a2– a Tensor2 to hold the squared tensor; with the same Mandel as this tensor
§Panics
A panic will occur if a2 has a different Mandel.
§Examples
use russell_lab::vec_approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[10.0, 20.0, 10.0],
[ 4.0, 5.0, 6.0],
[ 2.0, 3.0, 5.0],
], Mandel::General)?;
let mut a2 = Tensor2::new(Mandel::General);
a.squared(&mut a2);
let a2_correct = Tensor2::from_matrix(&[
[200.0, 330.0, 270.0],
[ 72.0, 123.0, 100.0],
[ 42.0, 70.0, 63.0],
], Mandel::General)?;
vec_approx_eq(a2.vector(), a2_correct.vector(), 1e-13);
Ok(())
}Sourcepub fn trace(&self) -> f64
pub fn trace(&self) -> f64
Calculates the trace
tr(σ) = σ:I = Σᵢ σᵢᵢ§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
approx_eq(a.trace(), 15.0, 1e-15);
Ok(())
}Sourcepub fn norm(&self) -> f64
pub fn norm(&self) -> f64
Calculates the Euclidean norm
norm(σ) = √(σ:σ)§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
approx_eq(a.norm(), f64::sqrt(285.0), 1e-13);
Ok(())
}Sourcepub fn deviator(&self, dev: &mut Tensor2)
pub fn deviator(&self, dev: &mut Tensor2)
Calculates the deviator tensor
dev(σ) = σ - ⅓ tr(σ) I§Output
dev– a Tensor2 to hold the deviator tensor; with the same Mandel as this tensor
§Panics
A panic will occur if dev has a different Mandel.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
], Mandel::General)?;
let mut dev = Tensor2::new(Mandel::General);
a.deviator(&mut dev);
approx_eq(dev.trace(), 0.0, 1e-15);
assert_eq!(
format!("{:.1}", dev.as_matrix()),
"┌ ┐\n\
│ -4.0 2.0 3.0 │\n\
│ 4.0 0.0 6.0 │\n\
│ 7.0 8.0 4.0 │\n\
└ ┘"
);
Ok(())
}Sourcepub fn deviator_norm(&self) -> f64
pub fn deviator_norm(&self) -> f64
Calculates the norm of the deviator tensor
norm(dev(σ)) = ‖s‖ = ‖ σ - ⅓ tr(σ) I ‖
‖s‖² = ⅓ [(σ₁₁-σ₂₂)² + (σ₂₂-σ₃₃)² + (σ₃₃-σ₁₁)²]
+ σ₁₂² + σ₂₃² + σ₁₃² + σ₂₁² + σ₃₂² + σ₃₁²Also the radius in the octahedral plane is:
r = ‖s‖ =§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[6.0, 1.0, 2.0],
[3.0, 12.0, 4.0],
[5.0, 6.0, 15.0],
], Mandel::General)?;
let mut dev = Tensor2::new(Mandel::General);
a.deviator(&mut dev);
approx_eq(dev.trace(), 0.0, 1e-15);
assert_eq!(
format!("{:.1}", dev.as_matrix()),
"┌ ┐\n\
│ -5.0 1.0 2.0 │\n\
│ 3.0 1.0 4.0 │\n\
│ 5.0 6.0 4.0 │\n\
└ ┘"
);
approx_eq(dev.norm(), f64::sqrt(133.0), 1e-15);
approx_eq(a.deviator_norm(), f64::sqrt(133.0), 1e-15);
Ok(())
}Sourcepub fn deviator_determinant(&self) -> f64
pub fn deviator_determinant(&self) -> f64
Calculates the determinant of the deviator tensor
det( σ - ⅓ tr(σ) I )§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[6.0, 1.0, 2.0],
[3.0, 12.0, 4.0],
[5.0, 6.0, 15.0],
], Mandel::General)?;
let mut dev = Tensor2::new(Mandel::General);
a.deviator(&mut dev);
approx_eq(dev.trace(), 0.0, 1e-15);
assert_eq!(
format!("{:.1}", dev.as_matrix()),
"┌ ┐\n\
│ -5.0 1.0 2.0 │\n\
│ 3.0 1.0 4.0 │\n\
│ 5.0 6.0 4.0 │\n\
└ ┘"
);
approx_eq(dev.determinant(), 134.0, 1e-13);
approx_eq(a.deviator_determinant(), 134.0, 1e-15);
Ok(())
}Sourcepub fn invariant_ii1(&self) -> f64
pub fn invariant_ii1(&self) -> f64
Calculates I1, the first principal invariant
I1 = trace(σ)§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let sig = Tensor2::from_matrix(&[
[50.0, 30.0, 20.0],
[30.0, -20.0, -10.0],
[20.0, -10.0, 10.0],
], Mandel::Symmetric)?;
approx_eq(sig.invariant_ii1(), 40.0, 1e-15);
Ok(())
}Sourcepub fn invariant_ii2(&self) -> f64
pub fn invariant_ii2(&self) -> f64
Calculates I2, the second principal invariant
I2 = ½ (trace(σ))² - ½ trace(σ·σ)§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let sig = Tensor2::from_matrix(&[
[50.0, 30.0, 20.0],
[30.0, -20.0, -10.0],
[20.0, -10.0, 10.0],
], Mandel::Symmetric)?;
approx_eq(sig.invariant_ii2(), -2100.0, 1e-12);
Ok(())
}Sourcepub fn invariant_ii3(&self) -> f64
pub fn invariant_ii3(&self) -> f64
Calculates I3, the third principal invariant
I3 = determinant(σ)§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let sig = Tensor2::from_matrix(&[
[50.0, 30.0, 20.0],
[30.0, -20.0, -10.0],
[20.0, -10.0, 10.0],
], Mandel::Symmetric)?;
approx_eq(sig.invariant_ii3(), -28000.0, 1e-15);
Ok(())
}Sourcepub fn invariant_jj2(&self) -> f64
pub fn invariant_jj2(&self) -> f64
Calculates J2, the second invariant of the deviatoric tensor corresponding to this tensor
s = deviator(σ)
J2 = -IIₛ = ½ trace(s·s) = ½ s : sᵀNote: if the tensor is symmetric, then:
J2 = ½ s : sᵀ = ½ s : s = ½ ‖s‖² (symmetric σ and s)Thus:
J2 = ½ r²where r = ‖s‖ is the radius on the octahedral plane.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let sig = Tensor2::from_matrix(&[
[ 2.0, -3.0, 4.0],
[-3.0, -5.0, 1.0],
[ 4.0, 1.0, 6.0],
], Mandel::Symmetric)?;
approx_eq(sig.invariant_jj2(), 57.0, 1e-14);
Ok(())
}Sourcepub fn invariant_jj3(&self) -> f64
pub fn invariant_jj3(&self) -> f64
Calculates J3, the second invariant of the deviatoric tensor corresponding to this tensor
s = deviator(σ)
J3 = IIIₛ = determinant(s)§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let sig = Tensor2::from_matrix(&[
[ 2.0, -3.0, 4.0],
[-3.0, -5.0, 1.0],
[ 4.0, 1.0, 6.0],
], Mandel::Symmetric)?;
approx_eq(sig.invariant_jj3(), -4.0, 1e-13);
Ok(())
}Sourcepub fn invariant_sigma_m(&self) -> f64
pub fn invariant_sigma_m(&self) -> f64
Returns the mean pressure invariant
σm = ⅓ trace(σ) = d / √3where d = trace(σ) √3 is the distance from the octahedral plane to the origin.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric)?;
approx_eq(a.invariant_sigma_m(), 2.0 / 3.0, 1e-15);
Ok(())
}Sourcepub fn invariant_sigma_d(&self) -> f64
pub fn invariant_sigma_d(&self) -> f64
Returns the deviatoric stress invariant (von Mises)
This quantity is also known as the von Mises effective invariant or equivalent stress.
σd = ‖s‖ √3/√2 = r √3/√2 = √3 √J2where r = ‖s‖ is the radius on the octahedral plane.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric)?;
approx_eq(a.invariant_sigma_d(), 1.0, 1e-15);
Ok(())
}Sourcepub fn invariant_eps_v(&self) -> f64
pub fn invariant_eps_v(&self) -> f64
Returns the volumetric strain invariant
εv = trace(ε) = d √3§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric)?;
approx_eq(a.invariant_eps_v(), 2.0, 1e-15);
Ok(())
}Sourcepub fn invariant_eps_d(&self) -> f64
pub fn invariant_eps_d(&self) -> f64
Returns the deviatoric strain invariant
εd = norm(dev(ε)) × √2/√3 = r √2/√3§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric)?;
approx_eq(a.invariant_eps_d(), 2.0 / 3.0, 1e-15);
Ok(())
}Sourcepub fn invariant_lode(&self) -> Option<f64>
pub fn invariant_lode(&self) -> Option<f64>
Returns the Lode invariant
3 √3 J3
l = cos(3θ) = ─────────────
2 pow(J2,1.5)§Returns
If J2 > TOL_J2, returns l. Otherwise, returns None.
§Examples
use russell_lab::approx_eq;
use russell_tensor::{Mandel, Tensor2, StrError};
fn main() -> Result<(), StrError> {
let a = Tensor2::from_matrix(&[
[1.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
], Mandel::Symmetric)?;
if let Some(l) = a.invariant_lode() {
approx_eq(l, -1.0, 1e-15);
}
Ok(())
}Sourcepub fn invariants_octahedral(&self) -> (f64, f64, Option<f64>)
pub fn invariants_octahedral(&self) -> (f64, f64, Option<f64>)
Calculates the octahedral invariants
§Input
Returns (distance, radius, lode) where:
distance– distancedfrom the octahedral plane to the originradius– radiusron the octahedral planelode– Lode invariantlin-1 ≤ lode ≤ 1
§Returns
If J2 > TOL_J2, returns l. Otherwise, returns None.
§Definitions
d = trace(T) / √3
r = ‖dev(T)‖
l = cos(3θ) = (3 √3 J3)/(2 pow(J2,1.5))