Struct Tensor2

Source
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

Source

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]);
}
Source

pub fn new_sym(two_dim: bool) -> Self

Allocates a symmetric Tensor2

Source

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)

Source

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) / √3
  • radius – 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 ≤ 1
  • 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/√2

In matrix form, the diagonal components of the tensor are the principal values (λ1, λ2, λ3):

┌          ┐
│ λ1  0  0 │
│  0 λ2  0 │
│  0  0 λ3 │
└          ┘
Source

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) / √3
  • radius – 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/√2

In matrix form, the diagonal components of the tensor are the principal values (λ1, λ2, λ3):

┌          ┐
│ λ1  0  0 │
│  0 λ2  0 │
│  0  0 λ3 │
└          ┘
Source

pub fn mandel(&self) -> Mandel

Returns the Mandel representation associated with this Tensor2

Source

pub fn dim(&self) -> usize

Returns the Mandel vector dimension (4, 6, or 9)

Source

pub fn vector(&self) -> &Vector

Returns an access to the underlying Mandel vector

Source

pub fn vector_mut(&mut self) -> &mut Vector

Returns a mutable access to the underlying Mandel vector

Source

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] and data[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(())
}
Source

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 basis
  • mandel – 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] and data[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(())
}
Source

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\
     └   ┘"
);
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

pub fn as_matrix_2d(&self) -> (f64, Matrix)

Returns a 2x2 matrix with the standard components

§Notes
  1. The matrix will have the standard components (not Mandel) and 2x2 dimension
  2. 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(())
}
Source

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(())
}
Source

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(())
}
Source

pub fn clear(&mut self)

Set all values to zero

Source

pub fn sym_set(&mut self, i: usize, j: usize, value: f64)

Sets the (i,j) component of a symmetric Tensor2

σᵢⱼ = value
§Notes
  1. Only the diagonal and upper-diagonal components need to be set.
  2. 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
  1. A panic will occur if the tensor is Mandel::General
  2. 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\
         └             ┘"
    );
}
Source

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
  1. Only the diagonal and upper-diagonal components need to be handled.
  2. 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
  1. A panic will occur if the indices are out of range
  2. A panic will occur if the tensor is Mandel::General
  3. 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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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 tensor
  • tolerance – 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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

pub fn invariant_sigma_m(&self) -> f64

Returns the mean pressure invariant

σm = ⅓ trace(σ) = d / √3

where 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(())
}
Source

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 √J2

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 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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

pub fn invariants_octahedral(&self) -> (f64, f64, Option<f64>)

Calculates the octahedral invariants

§Input

Returns (distance, radius, lode) where:

  • distance – distance d from the octahedral plane to the origin
  • radius – radius r on the octahedral plane
  • lode – Lode invariant l in -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))

Trait Implementations§

Source§

impl Clone for Tensor2

Source§

fn clone(&self) -> Tensor2

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Tensor2

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Tensor2

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Tensor2

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,