Skip to main content

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

1//! Hyperelastic solid constitutive models with internal variables.
2
3use crate::{
4    constitutive::{
5        ConstitutiveError,
6        solid::elastic::{
7            AppliedLoad,
8            internal_variables::{ElasticIV, bcs, bcs_block},
9        },
10    },
11    math::{
12        Quantity, Tensor, TensorArray, TensorTuple,
13        optimize::{
14            EqualityConstraint, FirstOrderOptimization, SecondOrderOptimizationBlock, SolveStrategy,
15        },
16    },
17    mechanics::{
18        DeformationGradient, FirstPiolaKirchhoffStress, FirstPiolaKirchhoffTangentStiffness,
19    },
20    units::EnergyDensity,
21};
22
23/// Required methods for hyperelastic solid constitutive models with internal variables.
24pub trait HyperelasticIV<V>
25where
26    Self: ElasticIV<V>,
27{
28    /// Calculates and returns the Helmholtz free energy density.
29    ///
30    /// ```math
31    /// a = a(\mathbf{F})
32    /// ```
33    fn helmholtz_free_energy_density(
34        &self,
35        deformation_gradient: &DeformationGradient,
36        internal_variables: &V,
37    ) -> Result<Quantity<EnergyDensity>, ConstitutiveError>;
38}
39
40/// First-order minimization methods for hyperelastic solid constitutive models with internal variables.
41pub trait FirstOrderMinimize<V> {
42    /// Type representing all residuals.
43    type Residuals;
44    /// Type representing all variables.
45    type Variables;
46    /// Solve for the unknown components of the deformation gradient under an applied load.
47    ///
48    /// ```math
49    /// \Pi(\mathbf{F},\boldsymbol{\lambda}) = a(\mathbf{F}) - \boldsymbol{\lambda}:(\mathbf{F} - \mathbf{F}_0) - \mathbf{P}_0:\mathbf{F}
50    /// ```
51    fn minimize(
52        &self,
53        applied_load: AppliedLoad,
54        solver: impl FirstOrderOptimization<Quantity<EnergyDensity>, Self::Residuals, Self::Variables>,
55    ) -> Result<(DeformationGradient, V), ConstitutiveError>;
56}
57
58/// Second-order minimization methods for hyperelastic solid constitutive models with internal variables.
59pub trait SecondOrderMinimize<V>
60where
61    Self: ElasticIV<V>,
62    V: Tensor,
63{
64    /// Solve for the unknown components of the deformation gradient under an applied load.
65    ///
66    /// ```math
67    /// \Pi(\mathbf{F},\boldsymbol{\lambda}) = a(\mathbf{F}) - \boldsymbol{\lambda}:(\mathbf{F} - \mathbf{F}_0) - \mathbf{P}_0:\mathbf{F}
68    /// ```
69    fn minimize(
70        &self,
71        applied_load: AppliedLoad,
72        solver: impl SecondOrderOptimizationBlock<
73            Quantity<EnergyDensity>,
74            DeformationGradient,
75            V,
76            FirstPiolaKirchhoffStress,
77            <Self as ElasticIV<V>>::Residual,
78            FirstPiolaKirchhoffTangentStiffness,
79            Self::TangentVu,
80            Self::TangentUv,
81            Self::TangentVv,
82        >,
83        strategy: SolveStrategy,
84    ) -> Result<(DeformationGradient, V), ConstitutiveError>;
85}
86
87impl<T, V> FirstOrderMinimize<V> for T
88where
89    T: HyperelasticIV<V>,
90    T: ElasticIV<V>,
91    V: Tensor,
92{
93    type Residuals = TensorTuple<FirstPiolaKirchhoffStress, <T as ElasticIV<V>>::Residual>;
94    type Variables = TensorTuple<DeformationGradient, V>;
95    fn minimize(
96        &self,
97        applied_load: AppliedLoad,
98        solver: impl FirstOrderOptimization<Quantity<EnergyDensity>, Self::Residuals, Self::Variables>,
99    ) -> Result<(DeformationGradient, V), ConstitutiveError> {
100        let (matrix, vector) = bcs(self, applied_load);
101        match solver.minimize(
102            |variables: &Self::Variables| {
103                let (deformation_gradient, internal_variables) = variables.into();
104                Ok(self.helmholtz_free_energy_density(deformation_gradient, internal_variables)?)
105            },
106            |variables: &Self::Variables| {
107                let (deformation_gradient, internal_variables) = variables.into();
108                Ok(TensorTuple::from((
109                    self.first_piola_kirchhoff_stress(deformation_gradient, internal_variables)?,
110                    self.internal_variables_residual(deformation_gradient, internal_variables)?,
111                )))
112            },
113            Self::Variables::from((
114                DeformationGradient::identity(),
115                self.internal_variables_initial(),
116            )),
117            EqualityConstraint::Linear(matrix, vector),
118        ) {
119            Ok(solution) => Ok(solution.into()),
120            Err(error) => Err(ConstitutiveError::Upstream(
121                format!("{error}"),
122                format!("{self:?}"),
123            )),
124        }
125    }
126}
127
128impl<T, V> SecondOrderMinimize<V> for T
129where
130    T: HyperelasticIV<V>,
131    V: Tensor,
132{
133    fn minimize(
134        &self,
135        applied_load: AppliedLoad,
136        solver: impl SecondOrderOptimizationBlock<
137            Quantity<EnergyDensity>,
138            DeformationGradient,
139            V,
140            FirstPiolaKirchhoffStress,
141            <Self as ElasticIV<V>>::Residual,
142            FirstPiolaKirchhoffTangentStiffness,
143            Self::TangentVu,
144            Self::TangentUv,
145            Self::TangentVv,
146        >,
147        strategy: SolveStrategy,
148    ) -> Result<(DeformationGradient, V), ConstitutiveError> {
149        let (constraint_external, constraint_internal) = bcs_block(self, applied_load);
150        match solver.minimize_block(
151            |deformation_gradient: &DeformationGradient, internal_variables: &V| {
152                Ok(self.helmholtz_free_energy_density(deformation_gradient, internal_variables)?)
153            },
154            |deformation_gradient: &DeformationGradient, internal_variables: &V| {
155                Ok(self.first_piola_kirchhoff_stress(deformation_gradient, internal_variables)?)
156            },
157            |deformation_gradient: &DeformationGradient, internal_variables: &V| {
158                Ok(self.internal_variables_residual(deformation_gradient, internal_variables)?)
159            },
160            |deformation_gradient: &DeformationGradient, internal_variables: &V| {
161                Ok(self.tangents(deformation_gradient, internal_variables)?)
162            },
163            (
164                DeformationGradient::identity(),
165                self.internal_variables_initial(),
166            ),
167            constraint_external,
168            constraint_internal,
169            None,
170            strategy,
171        ) {
172            Ok(solution) => Ok(solution),
173            Err(error) => Err(ConstitutiveError::Upstream(
174                format!("{error}"),
175                format!("{self:?}"),
176            )),
177        }
178    }
179}