use crate::{StrError, Tensor4};
use russell_lab::{Matrix, mat_inverse};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct VoigtReussHill {
pub kk_v: f64,
pub gg_v: f64,
pub kk_r: f64,
pub gg_r: f64,
pub kk_h: f64,
pub gg_h: f64,
pub aa_u: f64,
}
impl fmt::Display for VoigtReussHill {
#[rustfmt::skip]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match f.precision() {
Some(p) => {
write!(
f, "Kv = {:.p$}\nGv = {:.p$}\nKr = {:.p$}\nGr = {:.p$}\nKh = {:.p$}\nGh = {:.p$}\nAu = {:.p$}",
self.kk_v, self.gg_v, self.kk_r, self.gg_r, self.kk_h, self.gg_h, self.aa_u, p = p,
)
}
None => {
write!(
f, "Kv = {}\nGv = {}\nKr = {}\nGr = {}\nKh = {}\nGh = {}\nAu = {}",
self.kk_v, self.gg_v, self.kk_r, self.gg_r, self.kk_h, self.gg_h, self.aa_u
)
}
}
}
}
pub fn voigt_reuss_hill(ss: &mut Tensor4<6>, cc: &Tensor4<6>) -> Result<VoigtReussHill, StrError> {
let mut c_mat = Matrix::new(6, 6);
for m in 0..6 {
for n in 0..6 {
c_mat.set(m, n, cc.get(m, n));
}
}
let mut s_mat = Matrix::new(6, 6);
mat_inverse(&mut s_mat, &c_mat)?;
for m in 0..6 {
for n in 0..6 {
ss.set(m, n, s_mat.get(m, n));
}
}
let sum_c_diag = c_mat.get(0, 0) + c_mat.get(1, 1) + c_mat.get(2, 2);
let sum_c_off = c_mat.get(0, 1) + c_mat.get(0, 2) + c_mat.get(1, 2);
let sum_c_shear = c_mat.get(3, 3) + c_mat.get(4, 4) + c_mat.get(5, 5);
let sum_s_diag = s_mat.get(0, 0) + s_mat.get(1, 1) + s_mat.get(2, 2);
let sum_s_off = s_mat.get(0, 1) + s_mat.get(0, 2) + s_mat.get(1, 2);
let sum_s_shear = s_mat.get(3, 3) + s_mat.get(4, 4) + s_mat.get(5, 5);
let k_v = (sum_c_diag + 2.0 * sum_c_off) / 9.0;
let g_v = (sum_c_diag - sum_c_off + 1.5 * sum_c_shear) / 15.0;
let k_r = 1.0 / (sum_s_diag + 2.0 * sum_s_off);
let g_r = 15.0 / (4.0 * sum_s_diag - 4.0 * sum_s_off + 6.0 * sum_s_shear);
let k_h = (k_v + k_r) / 2.0;
let g_h = (g_v + g_r) / 2.0;
let a_u = 5.0 * (g_v / g_r) + (k_v / k_r) - 6.0;
Ok(VoigtReussHill {
kk_v: k_v,
gg_v: g_v,
kk_r: k_r,
gg_r: g_r,
kk_h: k_h,
gg_h: g_h,
aa_u: a_u,
})
}
#[cfg(test)]
mod tests {
use super::voigt_reuss_hill;
use crate::Tensor4;
use russell_lab::approx_eq;
#[test]
fn voigt_reuss_hill_works() {
let cc = Tensor4::<6>::from_std_array(&[
[
[[296.57, -35.27, 3.45], [-35.27, 144.76, -2.5], [3.45, -2.5, 125.5]],
[[-35.27, 110.56, 0.17], [110.56, 17.96, 0.02], [0.17, 0.02, -39.37]],
[[3.45, 0.17, 112.41], [0.17, 1.37, -31.15], [112.41, -31.15, 9.45]],
],
[
[[-35.27, 110.56, 0.17], [110.56, 17.96, 0.02], [0.17, 0.02, -39.37]],
[[144.76, 17.96, 1.37], [17.96, 273.54, -4.93], [1.37, -4.93, 74.42]],
[[-2.5, 0.02, -31.15], [0.02, -4.93, 113.03], [-31.15, 113.03, -18.81]],
],
[
[[3.45, 0.17, 112.41], [0.17, 1.37, -31.15], [112.41, -31.15, 9.45]],
[[-2.5, 0.02, -31.15], [0.02, -4.93, 113.03], [-31.15, 113.03, -18.81]],
[[125.5, -39.37, 9.45], [-39.37, 74.42, -18.81], [9.45, -18.81, 169.18]],
],
])
.unwrap();
let mut ss = Tensor4::<6>::new();
let vrh = voigt_reuss_hill(&mut ss, &cc).unwrap();
approx_eq(vrh.kk_v, 158.7388888888889, 1e-13);
approx_eq(vrh.gg_v, 93.5073333333333, 1e-13);
approx_eq(vrh.kk_r, 131.6385407574474, 1e-13);
approx_eq(vrh.gg_r, 74.87683938076444, 1e-13);
approx_eq(vrh.kk_h, 145.1887148231681, 1e-13);
approx_eq(vrh.gg_h, 84.1920863570489, 1e-13);
approx_eq(vrh.aa_u, 1.449945284449501, 1e-13);
assert_eq!(
format!("{:.3}", vrh),
"Kv = 158.739\n\
Gv = 93.507\n\
Kr = 131.639\n\
Gr = 74.877\n\
Kh = 145.189\n\
Gh = 84.192\n\
Au = 1.450"
);
}
}