use crate::{ONE_BY_3, SQRT_2, SQRT_2_BY_3, SQRT_3, SQRT_6};
pub struct SampleTensor2 {
pub desc: &'static str,
pub matrix: [[f64; 3]; 3],
pub deviator: [[f64; 3]; 3],
pub norm_a: f64,
pub ii1: f64,
pub ii2: f64,
pub ii3: f64,
pub norm_s: f64,
pub jj2: f64,
pub jj3: f64,
pub eigenvalues: Option<[f64; 3]>,
pub eigenprojectors: Option<[[[f64; 3]; 3]; 3]>,
}
pub struct SamplesTensor2 {}
impl SamplesTensor2 {
pub fn all_symmetric<'a>() -> Vec<&'a SampleTensor2> {
vec![
&SamplesTensor2::TENSOR_O,
&SamplesTensor2::TENSOR_I,
&SamplesTensor2::TENSOR_X,
&SamplesTensor2::TENSOR_Y,
&SamplesTensor2::TENSOR_Z,
&SamplesTensor2::TENSOR_U,
&SamplesTensor2::TENSOR_S,
&SamplesTensor2::COAL_01,
&SamplesTensor2::COAL_12,
]
}
pub const TENSOR_O: SampleTensor2 = SampleTensor2 {
desc: "Tensor O: symmetric tensor with all zero components",
matrix: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
deviator: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
norm_a: 0.0,
ii1: 0.0,
ii2: 0.0,
ii3: 0.0,
norm_s: 0.0,
jj2: 0.0,
jj3: 0.0,
eigenvalues: Some([0.0, 0.0, 0.0]),
eigenprojectors: Some([
[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
]),
};
pub const TENSOR_I: SampleTensor2 = SampleTensor2 {
desc: "Tensor I: symmetric diagonal tensor (identity tensor)",
matrix: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
deviator: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
norm_a: SQRT_3,
ii1: 3.0,
ii2: 3.0,
ii3: 1.0,
norm_s: 0.0,
jj2: 0.0,
jj3: 0.0,
eigenvalues: Some([1.0, 1.0, 1.0]),
eigenprojectors: Some([
[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
]),
};
pub const TENSOR_X: SampleTensor2 = SampleTensor2 {
desc: "Tensor X: symmetric 2D tensor with zero out-of-plane component (T22)",
matrix: [[7.0, 2.0, 0.0], [2.0, 4.0, 0.0], [0.0, 0.0, 0.0]],
deviator: [[10.0 / 3.0, 2.0, 0.0], [2.0, 1.0 / 3.0, 0.0], [0.0, 0.0, -11.0 / 3.0]],
norm_a: 8.54400374531753, ii1: 11.0,
ii2: 24.0,
ii3: 0.0,
norm_s: 7.0 * SQRT_2_BY_3,
jj2: 49.0 / 3.0,
jj3: 286.0 / 27.0,
eigenvalues: Some([8.0, 3.0, 0.0]),
eigenprojectors: Some([
[
[4.0 / 5.0, 2.0 / 5.0, 0.0],
[2.0 / 5.0, 1.0 / 5.0, 0.0],
[0.0, 0.0, 0.0],
],
[
[1.0 / 5.0, -2.0 / 5.0, 0.0],
[-2.0 / 5.0, 4.0 / 5.0, 0.0],
[0.0, 0.0, 0.0],
],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 1.0]],
]),
};
pub const TENSOR_Y: SampleTensor2 = SampleTensor2 {
desc: "Tensor Y: symmetric 2D tensor with zero out-of-plane component (T22)",
matrix: [[11.0, 3.0, 0.0], [3.0, 4.0, 0.0], [0.0, 0.0, 9.0]],
deviator: [[3.0, 3.0, 0.0], [3.0, -4.0, 0.0], [0.0, 0.0, 1.0]],
norm_a: 15.3622914957372, ii1: 24.0,
ii2: 170.0,
ii3: 315.0,
norm_s: 6.6332495807108, jj2: 22.0,
jj3: -21.0,
eigenvalues: Some([12.1097722286464, 9.0, 2.89022777135355]),
eigenprojectors: Some([
[
[0.8796283011826486, 0.32539568672798447, 0.0],
[0.32539568672798447, 0.12037169881735181, 0.0],
[0.0, 0.0, 0.0],
],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 1.0]],
[
[0.12037169881735181, -0.3253956867279844, 0.0],
[-0.3253956867279844, 0.8796283011826483, 0.0],
[0.0, 0.0, 0.0],
],
]),
};
pub const TENSOR_Z: SampleTensor2 = SampleTensor2 {
desc: "Tensor Z: symmetric tensor in 2D",
matrix: [[1.0, 2.0, 0.0], [2.0, 3.0, 0.0], [0.0, 0.0, 4.0]],
deviator: [[-5.0 / 3.0, 2.0, 0.0], [2.0, 1.0 / 3.0, 0.0], [0.0, 0.0, 4.0 / 3.0]],
norm_a: 5.8309518948453, ii1: 8.0,
ii2: 15.0,
ii3: -4.0,
norm_s: 3.55902608401044, jj2: 19.0 / 3.0,
jj3: -164.0 / 27.0,
eigenvalues: Some([4.23606797749979, 4.0, -0.23606797749978803]),
eigenprojectors: Some([
[
[0.2763932022500209, 0.4472135954999578, 0.0],
[0.4472135954999578, 0.7236067977499788, 0.0],
[0.0, 0.0, 0.0],
],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 1.0]],
[
[0.723606797749979, -0.44721359549995776, 0.0],
[-0.44721359549995776, 0.2763932022500208, 0.0],
[0.0, 0.0, 0.0],
],
]),
};
pub const TENSOR_U: SampleTensor2 = SampleTensor2 {
desc: "Tensor U: symmetric tensor in 3D",
matrix: [[1.0, 2.0, 3.0], [2.0, 4.0, 5.0], [3.0, 5.0, 6.0]],
deviator: [[-8.0 / 3.0, 2.0, 3.0], [2.0, 1.0 / 3.0, 5.0], [3.0, 5.0, 7.0 / 3.0]],
norm_a: 11.3578166916005, ii1: 11.0,
ii2: -4.0,
ii3: -1.0,
norm_s: 9.41629792788369, jj2: 133.0 / 3.0,
jj3: 3031.0 / 27.0,
eigenvalues: Some([11.3448142827621, 0.170915188827179, -0.515729471589257]),
eigenprojectors: Some([
[
[0.10757434232607616, 0.19384226684174424, 0.24171735309001374],
[0.19384226684174424, 0.3492916954160899, 0.43555961993175796],
[0.24171735309001374, 0.43555961993175796, 0.5431339622578341],
],
[
[0.34929169541608923, -0.4355596199317577, 0.19384226684174433],
[-0.4355596199317577, 0.5431339622578344, -0.24171735309001413],
[0.19384226684174433, -0.24171735309001413, 0.10757434232607645],
],
[
[0.5431339622578346, 0.24171735309001352, -0.435559619931758],
[0.24171735309001352, 0.10757434232607586, -0.1938422668417439],
[-0.435559619931758, -0.1938422668417439, 0.3492916954160896],
],
]),
};
pub const TENSOR_S: SampleTensor2 = SampleTensor2 {
desc: "Tensor S: symmetric tensor in 3D",
matrix: [[5.0, 4.0, 3.0], [4.0, 6.0, 1.0], [3.0, 1.0, 1.0]],
deviator: [[1.0, 4.0, 3.0], [4.0, 2.0, 1.0], [3.0, 1.0, -3.0]],
norm_a: 10.6770782520313, ii1: 12.0,
ii2: 15.0,
ii3: -21.0,
norm_s: 8.12403840463596, jj2: 33.0,
jj3: 47.0,
eigenvalues: Some([10.3557010334017, 2.46647252957463, -0.822173562976294]),
eigenprojectors: Some([
[
[0.45076513819893, 0.458387397610942, 0.193537908676564],
[0.458387397610942, 0.466138546401525, 0.196810557825709],
[0.193537908676564, 0.196810557825709, 0.0830963153995457],
],
[
[0.238267467437297, -0.34172021416371, 0.254407894197923],
[-0.34172021416371, 0.490090846325138, -0.364868611839051],
[0.254407894197923, -0.364868611839051, 0.271641686237565],
],
[
[0.310967394363773, -0.116667183447231, -0.447945802874487],
[-0.116667183447231, 0.0437706072733379, 0.168058054013342],
[-0.447945802874487, 0.168058054013342, 0.645261998362889],
],
]),
};
pub const TENSOR_R: SampleTensor2 = SampleTensor2 {
desc: "Tensor R: non-symmetric tensor",
matrix: [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]],
deviator: [[-4.0, 2.0, 3.0], [4.0, 0.0, 6.0], [7.0, 8.0, 4.0]],
norm_a: 16.8819430161341, ii1: 15.0,
ii2: -18.0,
ii3: 0.0,
norm_s: 14.4913767461894, jj2: 93.0,
jj3: 340.0,
eigenvalues: None,
eigenprojectors: None,
};
pub const TENSOR_T: SampleTensor2 = SampleTensor2 {
desc: "Tensor T: non-symmetric tensor",
matrix: [[6.0, 1.0, 2.0], [3.0, 12.0, 4.0], [5.0, 6.0, 15.0]],
deviator: [[-5.0, 1.0, 2.0], [3.0, 1.0, 4.0], [5.0, 6.0, 4.0]],
norm_a: 22.2710574513201, ii1: 33.0,
ii2: 305.0,
ii3: 827.0,
norm_s: 11.5325625946708, jj2: 58.0,
jj3: 134.0,
eigenvalues: None,
eigenprojectors: None,
};
pub const COAL_01: SampleTensor2 = SampleTensor2 {
desc: "Symmetric tensor with coalescent eigenvalues λ0 ≈ λ1 > λ2",
matrix: [
[11.0 / 6.0, 1.0 / (3.0 * SQRT_2), 1.0 / (2.0 * SQRT_3)],
[1.0 / (3.0 * SQRT_2), 5.0 / 3.0, -(1.0 / SQRT_6)],
[1.0 / (2.0 * SQRT_3), -(1.0 / SQRT_6), 3.0 / 2.0],
],
deviator: [
[1.0 / 6.0, 1.0 / (3.0 * SQRT_2), 1.0 / (2.0 * SQRT_3)],
[1.0 / (3.0 * SQRT_2), 0.0, -(1.0 / SQRT_6)],
[1.0 / (2.0 * SQRT_3), -(1.0 / SQRT_6), -1.0 / 6.0],
],
norm_a: 3.0,
ii1: 5.0,
ii2: 8.0,
ii3: 4.0,
norm_s: SQRT_2_BY_3,
jj2: ONE_BY_3,
jj3: -2.0 / 27.0,
eigenvalues: Some([2.0, 2.0, 1.0]),
eigenprojectors: Some([
[
[3.0 / 4.0, 0.0, SQRT_3 / 4.0],
[0.0, 0.0, 0.0],
[SQRT_3 / 4.0, 0.0, 1.0 / 4.0],
],
[
[1.0 / 12.0, 1.0 / (3.0 * SQRT_2), -1.0 / 4.0 * 1.0 / SQRT_3],
[1.0 / (3.0 * SQRT_2), 2.0 / 3.0, -(1.0 / SQRT_6)],
[-1.0 / 4.0 * 1.0 / SQRT_3, -(1.0 / SQRT_6), 1.0 / 4.0],
],
[
[1.0 / 6.0, -1.0 / 3.0 * 1.0 / SQRT_2, -1.0 / 2.0 * 1.0 / SQRT_3],
[-1.0 / 3.0 * 1.0 / SQRT_2, 1.0 / 3.0, 1.0 / SQRT_6],
[-1.0 / 2.0 * 1.0 / SQRT_3, 1.0 / SQRT_6, 1.0 / 2.0],
],
]),
};
pub const COAL_12: SampleTensor2 = SampleTensor2 {
desc: "Symmetric tensor with coalescent eigenvalues λ0 > λ1 ≈ λ2",
matrix: [
[5.0 / 3.0, SQRT_2 / 3.0, 0.0],
[SQRT_2 / 3.0, 4.0 / 3.0, 0.0],
[0.0, 0.0, 1.0],
],
deviator: [
[1.0 / 3.0, SQRT_2 / 3.0, 0.0],
[SQRT_2 / 3.0, 0.0, 0.0],
[0.0, 0.0, -1.0 / 3.0],
],
norm_a: SQRT_6,
ii1: 4.0,
ii2: 5.0,
ii3: 2.0,
norm_s: SQRT_2_BY_3,
jj2: ONE_BY_3,
jj3: 2.0 / 27.0,
eigenvalues: Some([2.0, 1.0, 1.0]),
eigenprojectors: Some([
[
[2.0 / 3.0, SQRT_2 / 3.0, 0.0],
[SQRT_2 / 3.0, 1.0 / 3.0, 0.0],
[0.0, 0.0, 0.0],
],
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 1.0]],
[
[1.0 / 3.0, -1.0 / 3.0 * SQRT_2, 0.0],
[-1.0 / 3.0 * SQRT_2, 2.0 / 3.0, 0.0],
[0.0, 0.0, 0.0],
],
]),
};
}
#[cfg(test)]
mod tests {
use super::{SampleTensor2, SamplesTensor2};
use russell_lab::{Matrix, approx_eq, mat_approx_eq};
fn check_symmetric(sample: &SampleTensor2) {
for i in 0..3 {
for j in 0..3 {
assert_eq!(sample.matrix[j][i], sample.matrix[i][j])
}
}
}
fn check_spectral(sample: &SampleTensor2, tolerance: f64) {
let l = sample.eigenvalues.unwrap();
let pps = sample.eigenprojectors.unwrap();
let mut m = Matrix::new(3, 3);
for i in 0..3 {
for j in 0..3 {
m.set(i, j, l[0] * pps[0][i][j] + l[1] * pps[1][i][j] + l[2] * pps[2][i][j]);
}
}
mat_approx_eq(&m, &sample.matrix, tolerance);
}
fn check_extra(sample: &SampleTensor2, tolerance: f64) {
let tr_a = sample.matrix[0][0] + sample.matrix[1][1] + sample.matrix[2][2];
let tr_s = sample.deviator[0][0] + sample.deviator[1][1] + sample.deviator[2][2];
assert_eq!(tr_a, sample.ii1);
approx_eq(tr_s, 0.0, tolerance);
approx_eq(sample.jj2, 0.5 * sample.norm_s * sample.norm_s, tolerance);
}
#[test]
fn samples_are_ok() {
for sample in SamplesTensor2::all_symmetric() {
check_symmetric(sample);
}
check_spectral(&SamplesTensor2::TENSOR_O, 1e-15);
check_spectral(&SamplesTensor2::TENSOR_I, 1e-15);
check_spectral(&SamplesTensor2::TENSOR_U, 1e-13);
check_spectral(&SamplesTensor2::TENSOR_S, 1e-13);
check_spectral(&SamplesTensor2::TENSOR_X, 1e-15);
check_spectral(&SamplesTensor2::TENSOR_Y, 1e-13);
check_spectral(&SamplesTensor2::TENSOR_Z, 1e-14);
check_spectral(&SamplesTensor2::COAL_01, 1e-15);
check_spectral(&SamplesTensor2::COAL_12, 1e-15);
check_extra(&SamplesTensor2::TENSOR_O, 1e-15);
check_extra(&SamplesTensor2::TENSOR_I, 1e-15);
check_extra(&SamplesTensor2::TENSOR_U, 1e-15);
check_extra(&SamplesTensor2::TENSOR_S, 1e-14);
check_extra(&SamplesTensor2::TENSOR_X, 1e-15);
check_extra(&SamplesTensor2::TENSOR_Y, 1e-14);
check_extra(&SamplesTensor2::TENSOR_Z, 1e-13);
check_extra(&SamplesTensor2::COAL_01, 1e-15);
check_extra(&SamplesTensor2::COAL_12, 1e-15);
}
}