1use serde::{Deserialize, Serialize};
4
5use crate::constitutive::HookeIsotropic;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PlaneStress {
11 pub material: HookeIsotropic,
12}
13
14impl PlaneStress {
15 pub fn new(material: HookeIsotropic) -> Self {
16 Self { material }
17 }
18
19 pub fn strain_from_stress_2d(&self, sxx: f64, syy: f64, txy: f64) -> (f64, f64, f64) {
24 let e = self.material.youngs_modulus;
25 let nu = self.material.poissons_ratio;
26 let g = self.material.shear_modulus();
27 let exx = (sxx - nu * syy) / e;
28 let eyy = (syy - nu * sxx) / e;
29 let gxy = txy / g;
30 (exx, eyy, gxy)
31 }
32
33 pub fn stress_from_strain_2d(&self, exx: f64, eyy: f64, gxy: f64) -> (f64, f64, f64) {
35 let e = self.material.youngs_modulus;
36 let nu = self.material.poissons_ratio;
37 let factor = e / (1.0 - nu * nu);
38 let sxx = factor * (exx + nu * eyy);
39 let syy = factor * (eyy + nu * exx);
40 let txy = self.material.shear_modulus() * gxy;
41 (sxx, syy, txy)
42 }
43
44 pub fn out_of_plane_strain(&self, sxx: f64, syy: f64) -> f64 {
46 let e = self.material.youngs_modulus;
47 let nu = self.material.poissons_ratio;
48 -nu * (sxx + syy) / e
49 }
50
51 pub fn stiffness_matrix_2d(&self) -> [[f64; 3]; 3] {
53 let e = self.material.youngs_modulus;
54 let nu = self.material.poissons_ratio;
55 let factor = e / (1.0 - nu * nu);
56 let g = e / (2.0 * (1.0 + nu));
57 [
58 [factor, factor * nu, 0.0],
59 [factor * nu, factor, 0.0],
60 [0.0, 0.0, g],
61 ]
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct PlaneStrain {
69 pub material: HookeIsotropic,
70}
71
72impl PlaneStrain {
73 pub fn new(material: HookeIsotropic) -> Self {
74 Self { material }
75 }
76
77 pub fn strain_from_stress_2d(&self, sxx: f64, syy: f64, txy: f64) -> (f64, f64, f64) {
79 let e = self.material.youngs_modulus;
80 let nu = self.material.poissons_ratio;
81 let g = self.material.shear_modulus();
82 let factor = (1.0 + nu) * (1.0 - 2.0 * nu);
83 let exx = ((1.0 - nu) * sxx - nu * syy) / (e * factor / (1.0 + nu));
84 let eyy = ((1.0 - nu) * syy - nu * sxx) / (e * factor / (1.0 + nu));
85 let gxy = txy / g;
86 (exx, eyy, gxy)
87 }
88
89 pub fn stress_from_strain_2d(&self, exx: f64, eyy: f64, gxy: f64) -> (f64, f64, f64) {
91 let e = self.material.youngs_modulus;
92 let nu = self.material.poissons_ratio;
93 let factor = e / ((1.0 + nu) * (1.0 - 2.0 * nu));
94 let sxx = factor * ((1.0 - nu) * exx + nu * eyy);
95 let syy = factor * (nu * exx + (1.0 - nu) * eyy);
96 let txy = self.material.shear_modulus() * gxy;
97 (sxx, syy, txy)
98 }
99
100 pub fn out_of_plane_stress(&self, sxx: f64, syy: f64) -> f64 {
102 self.material.poissons_ratio * (sxx + syy)
103 }
104
105 pub fn stiffness_matrix_2d(&self) -> [[f64; 3]; 3] {
107 let e = self.material.youngs_modulus;
108 let nu = self.material.poissons_ratio;
109 let factor = e / ((1.0 + nu) * (1.0 - 2.0 * nu));
110 let g = e / (2.0 * (1.0 + nu));
111 [
112 [factor * (1.0 - nu), factor * nu, 0.0],
113 [factor * nu, factor * (1.0 - nu), 0.0],
114 [0.0, 0.0, g],
115 ]
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use approx::assert_relative_eq;
123
124 #[test]
125 fn test_plane_stress_roundtrip() {
126 let mat = HookeIsotropic::new(200e9, 0.3);
127 let ps = PlaneStress::new(mat);
128 let (sxx, syy, txy) = (100e6, 50e6, 20e6);
129 let (exx, eyy, gxy) = ps.strain_from_stress_2d(sxx, syy, txy);
130 let (sxx2, syy2, txy2) = ps.stress_from_strain_2d(exx, eyy, gxy);
131 assert_relative_eq!(sxx, sxx2, epsilon = 1e-3);
132 assert_relative_eq!(syy, syy2, epsilon = 1e-3);
133 assert_relative_eq!(txy, txy2, epsilon = 1e-3);
134 }
135
136 #[test]
137 fn test_plane_strain_out_of_plane() {
138 let mat = HookeIsotropic::new(200e9, 0.3);
139 let pe = PlaneStrain::new(mat);
140 let s_zz = pe.out_of_plane_stress(100e6, 50e6);
141 assert_relative_eq!(s_zz, 0.3 * 150e6);
142 }
143
144 #[test]
145 fn test_plane_stress_out_of_plane_strain() {
146 let mat = HookeIsotropic::new(200e9, 0.3);
147 let ps = PlaneStress::new(mat);
148 let e_zz = ps.out_of_plane_strain(100e6, 50e6);
149 assert_relative_eq!(e_zz, -0.3 * 150e6 / 200e9);
150 }
151
152 #[test]
153 fn test_plane_stress_stiffness_symmetry() {
154 let mat = HookeIsotropic::new(200e9, 0.3);
155 let ps = PlaneStress::new(mat);
156 let c = ps.stiffness_matrix_2d();
157 assert_relative_eq!(c[0][1], c[1][0]);
158 }
159}