carapace_core/model/materials/
elastic_like.rs1use super::Material;
2
3impl Material {
4 pub fn elastic_pp(e: f64, eyp: f64) -> Self {
5 Material::ElasticPP { e, eyp, ep: 0.0 }
6 }
7}
8
9pub(super) fn evaluate_elastic(e: f64, strain: f64) -> (f64, f64, Material) {
10 (e * strain, e, Material::Elastic { e })
11}
12
13pub(super) fn evaluate_elastic_pp(e: f64, eyp: f64, ep: f64, strain: f64) -> (f64, f64, Material) {
14 let yield_stress = e * eyp;
15 let trial_stress = e * (strain - ep);
18 if trial_stress.abs() <= yield_stress {
24 (trial_stress, e, Material::ElasticPP { e, eyp, ep })
25 } else {
26 let stress = yield_stress.copysign(trial_stress);
27 let next_ep = strain - stress / e;
31 (
32 stress,
33 0.0,
34 Material::ElasticPP {
35 e,
36 eyp,
37 ep: next_ep,
38 },
39 )
40 }
41}
42
43pub(super) fn evaluate_gap(e: f64, gap: f64, strain: f64) -> (f64, f64, Material) {
44 let closure = strain + gap;
50 if closure <= 0.0 {
51 (e * closure, e, Material::Gap { e, gap })
52 } else {
53 (0.0, 0.0, Material::Gap { e, gap })
54 }
55}
56
57pub(super) fn evaluate_ent(e: f64, strain: f64) -> (f64, f64, Material) {
58 if strain <= 0.0 {
60 (e * strain, e, Material::Ent { e })
61 } else {
62 (0.0, 0.0, Material::Ent { e })
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn elastic_pp_clamps_symmetrically_on_first_loading() {
72 let m = Material::elastic_pp(100.0, 0.01);
76 assert_eq!(m.trial_stress_tangent(0.005), (0.5, 100.0));
77 assert_eq!(m.trial_stress_tangent(0.02), (1.0, 0.0));
78 assert_eq!(m.trial_stress_tangent(-0.02), (-1.0, 0.0));
79 }
80
81 #[test]
82 fn elastic_pp_remembers_permanent_set_after_commit() {
83 let m = Material::elastic_pp(100.0, 0.01);
84
85 let m = m.commit(0.02);
87 let Material::ElasticPP { ep, .. } = m else {
88 panic!()
89 };
90 assert!((ep - 0.01).abs() < 1e-12, "expected ep=0.01, got {ep}");
91
92 let (stress, tangent) = m.trial_stress_tangent(0.015);
99 assert!(
100 (stress - 0.5).abs() < 1e-12,
101 "expected elastic unload stress=0.5, got {stress}"
102 );
103 assert_eq!(
104 tangent, 100.0,
105 "should be elastic (unloading), not the plastic tangent"
106 );
107 }
108
109 #[test]
110 fn gap_only_engages_past_closure() {
111 let m = Material::Gap {
112 e: 100.0,
113 gap: 0.01,
114 };
115 assert_eq!(m.trial_stress_tangent(0.0), (0.0, 0.0));
116 assert_eq!(m.trial_stress_tangent(-0.005), (0.0, 0.0));
117 assert_eq!(
118 m.trial_stress_tangent(-0.02),
119 (100.0 * (-0.02 + 0.01), 100.0)
120 );
121 }
122
123 #[test]
124 fn ent_carries_no_tension() {
125 let m = Material::Ent { e: 100.0 };
126 assert_eq!(m.trial_stress_tangent(0.01), (0.0, 0.0));
127 assert_eq!(m.trial_stress_tangent(-0.01), (-1.0, 100.0));
128 }
129}