Skip to main content

conspire/constitutive/solid/hyperelastic/hencky/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    constitutive::{
6        ConstitutiveError,
7        solid::{Solid, TWO_THIRDS, elastic::Elastic, hyperelastic::Hyperelastic},
8    },
9    math::{ContractThirdFourthWithFirstSecond, IDENTITY, Quantity, Rank2, TensorRank4},
10    mechanics::{CauchyStress, CauchyTangentStiffness, Deformation, DeformationGradient},
11    units::{EnergyDensity, Stress},
12};
13
14#[doc = include_str!("doc.md")]
15#[derive(Clone, Debug)]
16pub struct Hencky {
17    /// The bulk modulus $`\kappa`$.
18    pub bulk_modulus: Quantity<Stress>,
19    /// The shear modulus $`\mu`$.
20    pub shear_modulus: Quantity<Stress>,
21}
22
23impl Solid for Hencky {
24    fn bulk_modulus(&self) -> Quantity<Stress> {
25        self.bulk_modulus
26    }
27    fn shear_modulus(&self) -> Quantity<Stress> {
28        self.shear_modulus
29    }
30}
31
32impl Elastic for Hencky {
33    #[doc = include_str!("cauchy_stress.md")]
34    fn cauchy_stress(
35        &self,
36        deformation_gradient: &DeformationGradient,
37    ) -> Result<CauchyStress, ConstitutiveError> {
38        let jacobian = self.jacobian(deformation_gradient)?;
39        let (deviatoric_strain, strain_trace) = (deformation_gradient
40            .left_cauchy_green()
41            .logm()
42            .map_err(|error| {
43            ConstitutiveError::upstream(error, self)
44        })? * 0.5)
45            .deviatoric_and_trace();
46        Ok(deviatoric_strain * (2.0 * self.shear_modulus() / jacobian)
47            + IDENTITY * (self.bulk_modulus() * strain_trace / jacobian))
48    }
49    #[doc = include_str!("cauchy_tangent_stiffness.md")]
50    fn cauchy_tangent_stiffness(
51        &self,
52        deformation_gradient: &DeformationGradient,
53    ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
54        let jacobian = self.jacobian(deformation_gradient)?;
55        let left_cauchy_green = deformation_gradient.left_cauchy_green();
56        let (deviatoric_strain, strain_trace) = (left_cauchy_green
57            .logm()
58            .map_err(|error| ConstitutiveError::upstream(error, self))?
59            * 0.5)
60            .deviatoric_and_trace();
61        let scaled_deformation_gradient = deformation_gradient * self.shear_modulus() / jacobian;
62        Ok((left_cauchy_green
63            .dlogm()
64            .map_err(|error| ConstitutiveError::upstream(error, self))?
65            .contract_third_fourth_with_first_second(
66                &(TensorRank4::dyad_il_jk(&scaled_deformation_gradient, &IDENTITY)
67                    + TensorRank4::dyad_ik_jl(&IDENTITY, &scaled_deformation_gradient)),
68            ))
69            + (TensorRank4::dyad_ij_kl(
70                &(IDENTITY
71                    * ((self.bulk_modulus() - TWO_THIRDS * self.shear_modulus()) / jacobian)
72                    - deviatoric_strain * (2.0 * self.shear_modulus() / jacobian)
73                    - IDENTITY * (self.bulk_modulus() * strain_trace / jacobian)),
74                &deformation_gradient.inverse_transpose(),
75            )))
76    }
77}
78
79impl Hyperelastic for Hencky {
80    #[doc = include_str!("helmholtz_free_energy_density.md")]
81    fn helmholtz_free_energy_density(
82        &self,
83        deformation_gradient: &DeformationGradient,
84    ) -> Result<Quantity<EnergyDensity>, ConstitutiveError> {
85        let _jacobian = self.jacobian(deformation_gradient)?;
86        let strain = deformation_gradient
87            .left_cauchy_green()
88            .logm()
89            .map_err(|error| ConstitutiveError::upstream(error, self))?
90            * 0.5;
91        Ok(self.shear_modulus() * strain.squared_trace()
92            + 0.5
93                * (self.bulk_modulus() - TWO_THIRDS * self.shear_modulus())
94                * strain.trace().powi(2))
95    }
96}