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

1#[cfg(test)]
2mod test;
3
4use crate::{
5    constitutive::{
6        Constitutive, ConstitutiveError, Parameters,
7        solid::{FIVE_THIRDS, Solid, TWO_THIRDS, elastic::Elastic, hyperelastic::Hyperelastic},
8    },
9    math::{IDENTITY, Rank2},
10    mechanics::{CauchyStress, CauchyTangentStiffness, Deformation, DeformationGradient, Scalar},
11};
12
13#[doc = include_str!("model.md")]
14#[derive(Debug)]
15pub struct Fung<P> {
16    parameters: P,
17}
18
19impl<P> Fung<P>
20where
21    P: Parameters,
22{
23    /// Returns the extra modulus.
24    pub fn extra_modulus(&self) -> &Scalar {
25        self.parameters.get(2)
26    }
27    /// Returns the exponent.
28    pub fn exponent(&self) -> &Scalar {
29        self.parameters.get(3)
30    }
31}
32
33impl<P> Constitutive<P> for Fung<P>
34where
35    P: Parameters,
36{
37    fn new(parameters: P) -> Self {
38        Self { parameters }
39    }
40}
41
42impl<P> Solid for Fung<P>
43where
44    P: Parameters,
45{
46    fn bulk_modulus(&self) -> &Scalar {
47        self.parameters.get(0)
48    }
49    fn shear_modulus(&self) -> &Scalar {
50        self.parameters.get(1)
51    }
52}
53
54impl<P> Elastic for Fung<P>
55where
56    P: Parameters,
57{
58    #[doc = include_str!("cauchy_stress.md")]
59    fn cauchy_stress(
60        &self,
61        deformation_gradient: &DeformationGradient,
62    ) -> Result<CauchyStress, ConstitutiveError> {
63        let jacobian = self.jacobian(deformation_gradient)?;
64        let isochoric_left_cauchy_green_deformation =
65            deformation_gradient.left_cauchy_green() / jacobian.powf(TWO_THIRDS);
66        let (
67            deviatoric_isochoric_left_cauchy_green_deformation,
68            isochoric_left_cauchy_green_deformation_trace,
69        ) = isochoric_left_cauchy_green_deformation.deviatoric_and_trace();
70        Ok(deviatoric_isochoric_left_cauchy_green_deformation
71            * ((self.shear_modulus()
72                + self.extra_modulus()
73                    * ((self.exponent() * (isochoric_left_cauchy_green_deformation_trace - 3.0))
74                        .exp()
75                        - 1.0))
76                / jacobian)
77            + IDENTITY * self.bulk_modulus() * 0.5 * (jacobian - 1.0 / jacobian))
78    }
79    #[doc = include_str!("cauchy_tangent_stiffness.md")]
80    fn cauchy_tangent_stiffness(
81        &self,
82        deformation_gradient: &DeformationGradient,
83    ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
84        let jacobian = self.jacobian(deformation_gradient)?;
85        let inverse_transpose_deformation_gradient = deformation_gradient.inverse_transpose();
86        let isochoric_left_cauchy_green_deformation =
87            deformation_gradient.left_cauchy_green() / jacobian.powf(TWO_THIRDS);
88        let (
89            deviatoric_isochoric_left_cauchy_green_deformation,
90            isochoric_left_cauchy_green_deformation_trace,
91        ) = isochoric_left_cauchy_green_deformation.deviatoric_and_trace();
92        let exponential =
93            (self.exponent() * (isochoric_left_cauchy_green_deformation_trace - 3.0)).exp();
94        let scaled_shear_modulus_0 = (self.shear_modulus()
95            + self.extra_modulus() * (exponential - 1.0))
96            / jacobian.powf(FIVE_THIRDS);
97        Ok(
98            (CauchyTangentStiffness::dyad_ik_jl(&IDENTITY, deformation_gradient)
99                + CauchyTangentStiffness::dyad_il_jk(deformation_gradient, &IDENTITY)
100                - CauchyTangentStiffness::dyad_ij_kl(&IDENTITY, deformation_gradient)
101                    * (TWO_THIRDS))
102                * scaled_shear_modulus_0
103                + CauchyTangentStiffness::dyad_ij_kl(
104                    &deviatoric_isochoric_left_cauchy_green_deformation,
105                    &((&deviatoric_isochoric_left_cauchy_green_deformation
106                        * &inverse_transpose_deformation_gradient)
107                        * (2.0 * self.exponent() * self.extra_modulus() * exponential / jacobian)),
108                )
109                + CauchyTangentStiffness::dyad_ij_kl(
110                    &(IDENTITY * (0.5 * self.bulk_modulus() * (jacobian + 1.0 / jacobian))
111                        - deformation_gradient.left_cauchy_green().deviatoric()
112                            * (scaled_shear_modulus_0 * FIVE_THIRDS)),
113                    &inverse_transpose_deformation_gradient,
114                ),
115        )
116    }
117}
118
119impl<P> Hyperelastic for Fung<P>
120where
121    P: Parameters,
122{
123    #[doc = include_str!("helmholtz_free_energy_density.md")]
124    fn helmholtz_free_energy_density(
125        &self,
126        deformation_gradient: &DeformationGradient,
127    ) -> Result<Scalar, ConstitutiveError> {
128        let jacobian = self.jacobian(deformation_gradient)?;
129        let scalar_term =
130            deformation_gradient.left_cauchy_green().trace() / jacobian.powf(TWO_THIRDS) - 3.0;
131        Ok(0.5
132            * ((self.shear_modulus() - self.extra_modulus()) * scalar_term
133                + self.extra_modulus() / self.exponent()
134                    * ((self.exponent() * scalar_term).exp() - 1.0)
135                + self.bulk_modulus() * (0.5 * (jacobian.powi(2) - 1.0) - jacobian.ln())))
136    }
137}