# Russell Tensor - Tensor analysis, calculus, and functions for continuum mechanics <!-- omit from toc -->
[](https://docs.rs/russell_tensor/)
_This crate is part of [Russell - Rust Scientific Library](https://github.com/cpmech/russell)_
## Contents <!-- omit from toc -->
- [Introduction](#introduction)
- [Capabilities](#capabilities)
- [Kelvin-Mandel notation](#kelvin-mandel-notation)
- [Documentation](#documentation)
- [Installation](#installation)
- [Setting Cargo.toml](#setting-cargotoml)
- [Optional features](#optional-features)
- [๐ Examples](#-examples)
- [Computing the Invariants](#computing-the-invariants)
- [Allocating Second Order Tensors](#allocating-second-order-tensors)
- [For developers](#for-developers)
- [Principal invariants (symmetric)](#principal-invariants-symmetric)
## Introduction
This library implements structures and functions for tensor analysis and calculus, with focus on applications in engineering and [Continuum Mechanics](https://en.wikipedia.org/wiki/Continuum_mechanics). The essential functionality for the targeted applications includes first-order, second-order, third-order, and fourth-order tensors, scalar "invariants," and derivatives.
### Capabilities
* `Tensor1` โ first-order tensors (vectors in R3) with operations such as the dot and cross products
* `Tensor2` โ second-order tensors (symmetric or not) with functions such as the determinant, inverse, norm, and invariants (principal, deviatoric, Lode, octahedral, ...)
* `Tensor3` โ third-order tensors (minor-symmetric or not)
* `Tensor4` โ fourth-order tensors (minor-symmetric or not)
* Operations between tensors โ addition, single and double contractions (dot and ddot), and dyadic products; most operations support both overwriting (`SET`) and accumulation (`ADD`)
* Analytical derivatives โ first and second derivatives of invariants and tensor functions (e.g., the inverse and squared tensors) with respect to tensors
* `EigenValuesT2`, `EigenProjsT2`, `EigenProjDerivsT2` โ eigenvalues, eigenprojectors, and the derivatives of the eigenprojectors of symmetric second-order tensors
* `LinElasticity` โ the linear elasticity equations for small-strain problems (Hooke's law)
* `PiezoDatabase` โ a database of piezoelectric materials (permittivity, piezoelectric, and stiffness tensors) loaded from JSON
* Constants โ identity, transposition, and projector tensors, as well as the `ADD`/`SET` operation selectors
* Polar decomposition โ `F = R U = V R` via the classic Eigen/SVD algorithms, Brannon's iterative algorithm, or the quaternion-based Higham & Noferini (2016) algorithm (`PolarAlgo`, `polar_decomp_mx`)
### Kelvin-Mandel notation
Internally, tensors are stored as vectors/matrices with components given with respect to the Kelvin-Mandel basis, i.e., the *Kelvin-Mandel* notation, a norm-preserving alternative to [Voigt notation](https://en.wikipedia.org/wiki/Voigt_notation). In the Kelvin-Mandel notation, a second-order tensor is mapped to a column matrix (vector), a third-order tensor is mapped to a rectangular matrix, and a fourth-order tensor is mapped to a square matrix. Factors such as `โ2` multiply some components to yield the norm-preserving mapping.
The dimension โ the const generic `N` of `Tensor2`/`Tensor4`, and `M`/`N` of `Tensor3` โ selects the representation:
* `9` โ all components (general): 9ร1 / 9ร3 / 3ร9 / 9ร9
* `6` โ symmetric `Tensor2` / minor-symmetric `Tensor3`/`Tensor4` (3D): 6ร1 / 6ร3 / 3ร6 / 6ร6
* `4` โ symmetric `Tensor2` / minor-symmetric `Tensor3`/`Tensor4` (2D): 4ร1 / 4ร3 / 3ร4 / 4ร4
The dimensions above correspond to `Tensor2` (vector), `Tensor3` (Case A / Case B rectangular matrix), and `Tensor4` (square matrix), respectively.
A `Tensor3` is stored as a rectangular Kelvin-Mandel matrix with dimensions `(M, N)` set by const generics. Two cases are considered, where `DIM` (the leading dimension) is one of 4, 6, or 9:
* **Case A** โ `(DIM, 3)`, i.e. `M = DIM` and `N = 3`: the Tensor3 acts on a `Tensor1` (vector) yielding a `Tensor2` (`T = H ยท u`)
* **Case B** โ `(3, DIM)`, i.e. `M = 3` and `N = DIM`: the Tensor3 acts on a `Tensor2` yielding a `Tensor1` (vector) (`v = M : S`)
For second-order tensors, the stored component order is:
| Representation | Stored components |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `9` (general) | `T11`, `T22`, `T33`, `(T12 + T21)/โ2`, `(T23 + T32)/โ2`, `(T13 + T31)/โ2`, `(T12 - T21)/โ2`, `(T23 - T32)/โ2`, `(T13 - T31)/โ2` |
| `6` (symmetric) | `T11`, `T22`, `T33`, `โ2 T12`, `โ2 T23`, `โ2 T13` |
| `4` (symmetric 2D) | `T11`, `T22`, `T33`, `โ2 T12` |
Use the `*_std*` constructors and accessors when working with ordinary Cartesian
components, such as `Tensor2::from_std_matrix` and `Tensor2::get_std`. Use the
accessors without `std` only when working directly with the stored
Kelvin-Mandel components. For example, an off-diagonal component `T12 = 4`
is stored as `โ2 ร 4` in a symmetric tensor, so `from_std_matrix` expects `4`
while `get(3)` returns `โ2 ร 4`.
### Documentation
* [](https://docs.rs/russell_tensor/) โ [russell_tensor documentation](https://docs.rs/russell_tensor/)
## Installation
This crate depends on `russell_lab`, which requires non-Rust high-performance libraries. [See the main README file for the steps to install these dependencies.](https://github.com/cpmech/russell)
### Setting Cargo.toml
[](https://crates.io/crates/russell_tensor)
๐ Check the crate version and update your Cargo.toml accordingly:
```toml
[dependencies]
russell_tensor = "*"
```
### Optional features
The following (Rust) features are available:
* `intel_mkl`: Use Intel MKL instead of OpenBLAS
Note that the [main README file](https://github.com/cpmech/russell) presents the steps to compile the required libraries according to each feature.
## ๐ Examples
This section illustrates how to use `russell_tensor`. See also:
* [More examples on the documentation](https://docs.rs/russell_tensor/)
* [Examples directory](https://github.com/cpmech/russell/tree/main/russell_tensor/examples)
### Computing the Invariants
```rust
use russell_tensor::{StrError, Tensor2};
fn main() -> Result<(), StrError> {
// Allocate a symmetric second-order tensor given the standard components
let a = Tensor2::<6>::from_std_matrix(&[
[1.0, 2.0, 3.0],
[2.0, 2.0, 4.0],
[3.0, 4.0, 3.0],
])?;
// Compute the principal invariants
let ii1 = a.invariant_ii1();
let ii2 = a.invariant_ii2();
let ii3 = a.invariant_ii3();
println!("I1 = {:.6}", ii1);
println!("I2 = {:.6}", ii2);
println!("I3 = {:.6}", ii3);
Ok(())
}
```
### Allocating Second Order Tensors
```rust
use russell_tensor::{StrError, Tensor2, SQRT_2};
fn main() -> Result<(), StrError> {
// Allocate a general second-order tensor given the standard components
let a = Tensor2::<9>::from_std_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),
"โ โ\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\
โ โ"
);
// Allocate a symmetric second-order tensor given the standard components
let b = Tensor2::<6>::from_std_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),
"โ โ\n\
โ 1.0 โ\n\
โ 2.0 โ\n\
โ 3.0 โ\n\
โ 4.0 โ\n\
โ 5.0 โ\n\
โ 6.0 โ\n\
โ โ"
);
// Allocate a symmetric second-order tensor given the standard components for 2D problems
let c = Tensor2::<4>::from_std_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),
"โ โ\n\
โ 1.0 โ\n\
โ 2.0 โ\n\
โ 3.0 โ\n\
โ 4.0 โ\n\
โ โ"
);
Ok(())
}
```
## For developers
* This crate depends on `russell_lab`, which requires non-Rust high-performance libraries (see the Installation section)
* Run the examples with `cargo run --example <name>`