use serde::{Deserialize, Serialize};
use crate::constitutive::HookeIsotropic;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaneStress {
pub material: HookeIsotropic,
}
impl PlaneStress {
pub fn new(material: HookeIsotropic) -> Self {
Self { material }
}
pub fn strain_from_stress_2d(&self, sxx: f64, syy: f64, txy: f64) -> (f64, f64, f64) {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let g = self.material.shear_modulus();
let exx = (sxx - nu * syy) / e;
let eyy = (syy - nu * sxx) / e;
let gxy = txy / g;
(exx, eyy, gxy)
}
pub fn stress_from_strain_2d(&self, exx: f64, eyy: f64, gxy: f64) -> (f64, f64, f64) {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let factor = e / (1.0 - nu * nu);
let sxx = factor * (exx + nu * eyy);
let syy = factor * (eyy + nu * exx);
let txy = self.material.shear_modulus() * gxy;
(sxx, syy, txy)
}
pub fn out_of_plane_strain(&self, sxx: f64, syy: f64) -> f64 {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
-nu * (sxx + syy) / e
}
pub fn stiffness_matrix_2d(&self) -> [[f64; 3]; 3] {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let factor = e / (1.0 - nu * nu);
let g = e / (2.0 * (1.0 + nu));
[
[factor, factor * nu, 0.0],
[factor * nu, factor, 0.0],
[0.0, 0.0, g],
]
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaneStrain {
pub material: HookeIsotropic,
}
impl PlaneStrain {
pub fn new(material: HookeIsotropic) -> Self {
Self { material }
}
pub fn strain_from_stress_2d(&self, sxx: f64, syy: f64, txy: f64) -> (f64, f64, f64) {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let g = self.material.shear_modulus();
let factor = (1.0 + nu) * (1.0 - 2.0 * nu);
let exx = ((1.0 - nu) * sxx - nu * syy) / (e * factor / (1.0 + nu));
let eyy = ((1.0 - nu) * syy - nu * sxx) / (e * factor / (1.0 + nu));
let gxy = txy / g;
(exx, eyy, gxy)
}
pub fn stress_from_strain_2d(&self, exx: f64, eyy: f64, gxy: f64) -> (f64, f64, f64) {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let factor = e / ((1.0 + nu) * (1.0 - 2.0 * nu));
let sxx = factor * ((1.0 - nu) * exx + nu * eyy);
let syy = factor * (nu * exx + (1.0 - nu) * eyy);
let txy = self.material.shear_modulus() * gxy;
(sxx, syy, txy)
}
pub fn out_of_plane_stress(&self, sxx: f64, syy: f64) -> f64 {
self.material.poissons_ratio * (sxx + syy)
}
pub fn stiffness_matrix_2d(&self) -> [[f64; 3]; 3] {
let e = self.material.youngs_modulus;
let nu = self.material.poissons_ratio;
let factor = e / ((1.0 + nu) * (1.0 - 2.0 * nu));
let g = e / (2.0 * (1.0 + nu));
[
[factor * (1.0 - nu), factor * nu, 0.0],
[factor * nu, factor * (1.0 - nu), 0.0],
[0.0, 0.0, g],
]
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_plane_stress_roundtrip() {
let mat = HookeIsotropic::new(200e9, 0.3);
let ps = PlaneStress::new(mat);
let (sxx, syy, txy) = (100e6, 50e6, 20e6);
let (exx, eyy, gxy) = ps.strain_from_stress_2d(sxx, syy, txy);
let (sxx2, syy2, txy2) = ps.stress_from_strain_2d(exx, eyy, gxy);
assert_relative_eq!(sxx, sxx2, epsilon = 1e-3);
assert_relative_eq!(syy, syy2, epsilon = 1e-3);
assert_relative_eq!(txy, txy2, epsilon = 1e-3);
}
#[test]
fn test_plane_strain_out_of_plane() {
let mat = HookeIsotropic::new(200e9, 0.3);
let pe = PlaneStrain::new(mat);
let s_zz = pe.out_of_plane_stress(100e6, 50e6);
assert_relative_eq!(s_zz, 0.3 * 150e6);
}
#[test]
fn test_plane_stress_out_of_plane_strain() {
let mat = HookeIsotropic::new(200e9, 0.3);
let ps = PlaneStress::new(mat);
let e_zz = ps.out_of_plane_strain(100e6, 50e6);
assert_relative_eq!(e_zz, -0.3 * 150e6 / 200e9);
}
#[test]
fn test_plane_stress_stiffness_symmetry() {
let mat = HookeIsotropic::new(200e9, 0.3);
let ps = PlaneStress::new(mat);
let c = ps.stiffness_matrix_2d();
assert_relative_eq!(c[0][1], c[1][0]);
}
}