Skip to main content

conspire/constitutive/cohesive/elastic/
mod.rs

1//! Elastic cohesive constitutive models.
2
3use crate::{
4    constitutive::{Constitutive, ConstitutiveError, cohesive::Cohesive},
5    math::{Current, Quantity, Tensor, TensorArray, TensorRank2, TensorTuple},
6    mechanics::{Normal, Separation, Traction},
7    units::{Length, Stress, StressPerLength},
8};
9
10type Dyad = TensorRank2<3, Current, Current>;
11type DyadSeparation = TensorRank2<3, Current, Current, Length>;
12
13pub(crate) type StiffnessCohesive = TensorTuple<
14    TensorRank2<3, Current, Current, StressPerLength>,
15    TensorRank2<3, Current, Current, Stress>,
16>;
17
18/// Required methods for elastic cohesive constitutive models.
19pub trait Elastic
20where
21    Self: Cohesive,
22{
23    fn traction(
24        &self,
25        separation: Separation,
26        normal: Normal,
27    ) -> Result<Traction, ConstitutiveError> {
28        let normal_component = &separation * &normal;
29        let normal_separation = &normal * normal_component;
30        let tangential_separation = separation - normal_separation;
31        let tangential_component = tangential_separation.norm();
32        let (normal_traction, tangential_traction) =
33            self.tractions(normal_component, tangential_component)?;
34        if !tangential_component.is_zero() {
35            Ok(normal * normal_traction
36                + (tangential_separation / tangential_component) * tangential_traction)
37        } else {
38            Ok(normal * normal_traction)
39        }
40    }
41    /// Calculates and returns the normal and tangential tractions.
42    fn tractions(
43        &self,
44        normal_separation: Quantity<Length>,
45        tangential_separation: Quantity<Length>,
46    ) -> Result<(Quantity<Stress>, Quantity<Stress>), ConstitutiveError>;
47    fn stiffness(
48        &self,
49        separation: Separation,
50        normal: Normal,
51    ) -> Result<StiffnessCohesive, ConstitutiveError> {
52        let normal_component = &separation * &normal;
53        let normal_separation = &normal * normal_component;
54        let tangential_separation = &separation - normal_separation;
55        let tangential_component = tangential_separation.norm();
56        let (normal_traction, tangential_traction) =
57            self.tractions(normal_component, tangential_component)?;
58        let (k_nn, k_tt) = self.stiffnesses(normal_component, tangential_component)?;
59        let (tangent, ratio, q_t) = if !tangential_component.is_zero() {
60            (
61                tangential_separation / tangential_component,
62                normal_component / tangential_component,
63                tangential_traction / tangential_component,
64            )
65        } else {
66            (Normal::zero(), Quantity::zero(), k_tt)
67        };
68        let nn = Dyad::from((&normal, &normal));
69        let nu = DyadSeparation::from((&normal, &separation));
70        let tt = Dyad::from((&tangent, &tangent));
71        let tu = DyadSeparation::from((&tangent, &separation));
72        let identity = Dyad::identity();
73        let stiffness_u = nn * (k_nn - q_t) + tt * (k_tt - q_t) + &identity * q_t;
74        let stiffness_n = nu * (k_nn - q_t)
75            + identity * (normal_traction - tangential_traction * ratio)
76            - tu * ((k_tt - q_t) * ratio);
77        Ok(TensorTuple(stiffness_u, stiffness_n))
78    }
79    /// Calculates and returns the normal and tangential stiffnesses.
80    fn stiffnesses(
81        &self,
82        normal_separation: Quantity<Length>,
83        tangential_separation: Quantity<Length>,
84    ) -> Result<(Quantity<StressPerLength>, Quantity<StressPerLength>), ConstitutiveError>;
85}
86
87/// The linear elastic cohesive constitutive model.
88#[derive(Clone, Debug)]
89pub struct LinearElastic {
90    /// The normal stiffness $`k_n`$.
91    pub normal_stiffness: Quantity<StressPerLength>,
92    /// The tangential stiffness $`k_t`$.
93    pub tangential_stiffness: Quantity<StressPerLength>,
94}
95
96impl Constitutive for LinearElastic {}
97
98impl Cohesive for LinearElastic {}
99
100impl LinearElastic {
101    /// Returns the normal stiffness.
102    fn normal_stiffness(&self) -> Quantity<StressPerLength> {
103        self.normal_stiffness
104    }
105    /// Returns the tangential stiffness.
106    fn tangential_stiffness(&self) -> Quantity<StressPerLength> {
107        self.tangential_stiffness
108    }
109}
110
111impl Elastic for LinearElastic {
112    fn tractions(
113        &self,
114        normal_separation: Quantity<Length>,
115        tangential_separation: Quantity<Length>,
116    ) -> Result<(Quantity<Stress>, Quantity<Stress>), ConstitutiveError> {
117        Ok((
118            self.normal_stiffness() * normal_separation,
119            self.tangential_stiffness() * tangential_separation,
120        ))
121    }
122    fn stiffnesses(
123        &self,
124        _normal_separation: Quantity<Length>,
125        _tangential_separation: Quantity<Length>,
126    ) -> Result<(Quantity<StressPerLength>, Quantity<StressPerLength>), ConstitutiveError> {
127        Ok((self.normal_stiffness(), self.tangential_stiffness()))
128    }
129}