conspire/constitutive/hybrid/elastic/multiplicative/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    constitutive::{
6        ConstitutiveError,
7        hybrid::{Hybrid, Multiplicative, MultiplicativeTrait},
8        solid::{Solid, elastic::Elastic},
9    },
10    math::{
11        IDENTITY_10, Rank2, TensorRank2,
12        optimize::{EqualityConstraint, GradientDescent, ZerothOrderRootFinding},
13    },
14    mechanics::{
15        CauchyStress, CauchyTangentStiffness, DeformationGradient, FirstPiolaKirchhoffStress,
16        FirstPiolaKirchhoffTangentStiffness, Scalar, SecondPiolaKirchhoffStress,
17        SecondPiolaKirchhoffTangentStiffness,
18    },
19};
20use std::fmt::Debug;
21
22impl<C1, C2> Solid for Multiplicative<C1, C2>
23where
24    C1: Debug,
25    C2: Debug,
26{
27    /// Dummy method that will panic.
28    fn bulk_modulus(&self) -> &Scalar {
29        panic!()
30    }
31    /// Dummy method that will panic.
32    fn shear_modulus(&self) -> &Scalar {
33        panic!()
34    }
35}
36
37impl<C1, C2> Elastic for Multiplicative<C1, C2>
38where
39    C1: Elastic,
40    C2: Elastic,
41{
42    /// Calculates and returns the Cauchy stress.
43    ///
44    /// ```math
45    /// \boldsymbol{\sigma}(\mathbf{F}) = \frac{1}{J_2}\,\boldsymbol{\sigma}_1(\mathbf{F}_1)
46    /// ```
47    fn cauchy_stress(
48        &self,
49        deformation_gradient: &DeformationGradient,
50    ) -> Result<CauchyStress, ConstitutiveError> {
51        let (deformation_gradient_1, deformation_gradient_2) =
52            self.deformation_gradients(deformation_gradient)?;
53        Ok(self
54            .constitutive_model_1()
55            .cauchy_stress(&deformation_gradient_1)?
56            / deformation_gradient_2.determinant())
57    }
58    /// Dummy method that will panic.
59    fn cauchy_tangent_stiffness(
60        &self,
61        _: &DeformationGradient,
62    ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
63        panic!()
64    }
65    /// Calculates and returns the first Piola-Kirchhoff stress.
66    ///
67    /// ```math
68    /// \mathbf{P}(\mathbf{F}) = \mathbf{P}_1(\mathbf{F}_1)\cdot\mathbf{F}_2^{-T}
69    /// ```
70    fn first_piola_kirchhoff_stress(
71        &self,
72        deformation_gradient: &DeformationGradient,
73    ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
74        let (deformation_gradient_1, deformation_gradient_2) =
75            self.deformation_gradients(deformation_gradient)?;
76        let deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0> =
77            deformation_gradient_2.inverse_transpose().into();
78        Ok(self
79            .constitutive_model_1()
80            .first_piola_kirchhoff_stress(&deformation_gradient_1)?
81            * deformation_gradient_2_inverse_transpose)
82    }
83    /// Dummy method that will panic.
84    fn first_piola_kirchhoff_tangent_stiffness(
85        &self,
86        _: &DeformationGradient,
87    ) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
88        panic!()
89    }
90    /// Calculates and returns the second Piola-Kirchhoff stress.
91    ///
92    /// ```math
93    /// \mathbf{S}(\mathbf{F}) = \mathbf{F}_2^{-1}\cdot\mathbf{S}_1(\mathbf{F}_1)\cdot\mathbf{F}_2^{-T}
94    /// ```
95    fn second_piola_kirchhoff_stress(
96        &self,
97        deformation_gradient: &DeformationGradient,
98    ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
99        let (deformation_gradient_1, deformation_gradient_2) =
100            self.deformation_gradients(deformation_gradient)?;
101        let deformation_gradient_2_inverse: TensorRank2<3, 0, 0> =
102            deformation_gradient_2.inverse().into();
103        Ok(&deformation_gradient_2_inverse
104            * self
105                .constitutive_model_1()
106                .second_piola_kirchhoff_stress(&deformation_gradient_1)?
107            * deformation_gradient_2_inverse.transpose())
108    }
109    /// Dummy method that will panic.
110    fn second_piola_kirchhoff_tangent_stiffness(
111        &self,
112        _: &DeformationGradient,
113    ) -> Result<SecondPiolaKirchhoffTangentStiffness, ConstitutiveError> {
114        panic!()
115    }
116}
117
118impl<C1, C2> MultiplicativeTrait for Multiplicative<C1, C2>
119where
120    C1: Elastic,
121    C2: Elastic,
122{
123    fn deformation_gradients(
124        &self,
125        deformation_gradient: &DeformationGradient,
126    ) -> Result<(DeformationGradient, DeformationGradient), ConstitutiveError> {
127        if deformation_gradient.is_identity() {
128            Ok((IDENTITY_10, IDENTITY_10))
129        } else {
130            match GradientDescent::default().root(
131                |deformation_gradient_2: &DeformationGradient| {
132                    let deformation_gradient_1: DeformationGradient =
133                        (deformation_gradient * deformation_gradient_2.inverse()).into();
134                    let deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0> =
135                        deformation_gradient_2.inverse_transpose().into();
136                    let right_hand_side: FirstPiolaKirchhoffStress = (deformation_gradient_1
137                        .transpose()
138                        * self
139                            .constitutive_model_1()
140                            .first_piola_kirchhoff_stress(&deformation_gradient_1)?
141                        * deformation_gradient_2_inverse_transpose)
142                        .into();
143                    Ok(self
144                        .constitutive_model_2()
145                        .first_piola_kirchhoff_stress(deformation_gradient_2)?
146                        - right_hand_side)
147                },
148                IDENTITY_10,
149                EqualityConstraint::None,
150            ) {
151                Ok(deformation_gradient_2) => {
152                    let deformation_gradient_1 =
153                        (deformation_gradient * deformation_gradient_2.inverse()).into();
154                    Ok((deformation_gradient_1, deformation_gradient_2))
155                }
156                Err(error) => Err(ConstitutiveError::Upstream(
157                    format!("{error}"),
158                    format!("{self:?}"),
159                )),
160            }
161        }
162    }
163}