conspire/constitutive/solid/elastic/
mod.rs1#![doc = include_str!("doc.md")]
6
7#[cfg(feature = "doc")]
8pub mod doc;
9
10#[cfg(test)]
11pub mod test;
12
13pub mod internal_variables;
14
15mod almansi_hamel;
16mod hencky;
17mod saint_venant_kirchhoff;
18
19pub use self::{
20 almansi_hamel::AlmansiHamel, hencky::Hencky, saint_venant_kirchhoff::SaintVenantKirchhoff,
21};
22
23use super::*;
24use crate::math::{
25 Matrix, Vector,
26 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
27};
28
29pub enum AppliedLoad {
31 UniaxialStress(Scalar),
33 BiaxialStress(Scalar, Scalar),
35}
36
37pub trait Elastic
39where
40 Self: Solid,
41{
42 fn cauchy_stress(
48 &self,
49 deformation_gradient: &DeformationGradient,
50 ) -> Result<CauchyStress, ConstitutiveError> {
51 Ok(deformation_gradient
52 * self.second_piola_kirchhoff_stress(deformation_gradient)?
53 * deformation_gradient.transpose()
54 / deformation_gradient.determinant())
55 }
56 fn cauchy_tangent_stiffness(
62 &self,
63 deformation_gradient: &DeformationGradient,
64 ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
65 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
66 let cauchy_stress = self.cauchy_stress(deformation_gradient)?;
67 let some_stress = &cauchy_stress * &deformation_gradient_inverse_transpose;
68 Ok(self
69 .second_piola_kirchhoff_tangent_stiffness(deformation_gradient)?
70 .contract_first_second_with_second(deformation_gradient, deformation_gradient)
71 / deformation_gradient.determinant()
72 - CauchyTangentStiffness::dyad_ij_kl(
73 &cauchy_stress,
74 &deformation_gradient_inverse_transpose,
75 )
76 + CauchyTangentStiffness::dyad_il_kj(&some_stress, &IDENTITY)
77 + CauchyTangentStiffness::dyad_ik_jl(&IDENTITY, &some_stress))
78 }
79 fn first_piola_kirchhoff_stress(
85 &self,
86 deformation_gradient: &DeformationGradient,
87 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
88 Ok(self.cauchy_stress(deformation_gradient)?
89 * deformation_gradient.inverse_transpose()
90 * deformation_gradient.determinant())
91 }
92 fn first_piola_kirchhoff_tangent_stiffness(
98 &self,
99 deformation_gradient: &DeformationGradient,
100 ) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
101 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
102 let first_piola_kirchhoff_stress =
103 self.first_piola_kirchhoff_stress(deformation_gradient)?;
104 Ok(self
105 .cauchy_tangent_stiffness(deformation_gradient)?
106 .contract_second_with_first(&deformation_gradient_inverse_transpose)
107 * deformation_gradient.determinant()
108 + FirstPiolaKirchhoffTangentStiffness::dyad_ij_kl(
109 &first_piola_kirchhoff_stress,
110 &deformation_gradient_inverse_transpose,
111 )
112 - FirstPiolaKirchhoffTangentStiffness::dyad_il_kj(
113 &first_piola_kirchhoff_stress,
114 &deformation_gradient_inverse_transpose,
115 ))
116 }
117 fn second_piola_kirchhoff_stress(
123 &self,
124 deformation_gradient: &DeformationGradient,
125 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
126 Ok(deformation_gradient.inverse()
127 * self.first_piola_kirchhoff_stress(deformation_gradient)?)
128 }
129 fn second_piola_kirchhoff_tangent_stiffness(
135 &self,
136 deformation_gradient: &DeformationGradient,
137 ) -> Result<SecondPiolaKirchhoffTangentStiffness, ConstitutiveError> {
138 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
139 let deformation_gradient_inverse = deformation_gradient_inverse_transpose.transpose();
140 let second_piola_kirchhoff_stress =
141 self.second_piola_kirchhoff_stress(deformation_gradient)?;
142 Ok(self
143 .cauchy_tangent_stiffness(deformation_gradient)?
144 .contract_first_second_with_second(
145 &deformation_gradient_inverse,
146 &deformation_gradient_inverse,
147 )
148 * deformation_gradient.determinant()
149 + SecondPiolaKirchhoffTangentStiffness::dyad_ij_kl(
150 &second_piola_kirchhoff_stress,
151 &deformation_gradient_inverse_transpose,
152 )
153 - SecondPiolaKirchhoffTangentStiffness::dyad_il_kj(
154 &second_piola_kirchhoff_stress,
155 &deformation_gradient_inverse_transpose,
156 )
157 - SecondPiolaKirchhoffTangentStiffness::dyad_ik_jl(
158 &deformation_gradient_inverse,
159 &second_piola_kirchhoff_stress,
160 ))
161 }
162}
163
164pub trait ZerothOrderRoot {
166 fn root(
172 &self,
173 applied_load: AppliedLoad,
174 solver: impl ZerothOrderRootFinding<DeformationGradient>,
175 ) -> Result<DeformationGradient, ConstitutiveError>;
176}
177
178pub trait FirstOrderRoot {
180 fn root(
186 &self,
187 applied_load: AppliedLoad,
188 solver: impl FirstOrderRootFinding<
189 FirstPiolaKirchhoffStress,
190 FirstPiolaKirchhoffTangentStiffness,
191 DeformationGradient,
192 >,
193 ) -> Result<DeformationGradient, ConstitutiveError>;
194}
195
196impl<T> ZerothOrderRoot for T
197where
198 T: Elastic,
199{
200 fn root(
201 &self,
202 applied_load: AppliedLoad,
203 solver: impl ZerothOrderRootFinding<DeformationGradient>,
204 ) -> Result<DeformationGradient, ConstitutiveError> {
205 let (matrix, vector) = bcs(applied_load);
206 match solver.root(
207 |deformation_gradient: &DeformationGradient| {
208 Ok(self.first_piola_kirchhoff_stress(deformation_gradient)?)
209 },
210 DeformationGradient::identity(),
211 EqualityConstraint::Linear(matrix, vector),
212 ) {
213 Ok(deformation_gradient) => Ok(deformation_gradient),
214 Err(error) => Err(ConstitutiveError::Upstream(
215 format!("{error}"),
216 format!("{self:?}"),
217 )),
218 }
219 }
220}
221
222impl<T> FirstOrderRoot for T
223where
224 T: Elastic,
225{
226 fn root(
227 &self,
228 applied_load: AppliedLoad,
229 solver: impl FirstOrderRootFinding<
230 FirstPiolaKirchhoffStress,
231 FirstPiolaKirchhoffTangentStiffness,
232 DeformationGradient,
233 >,
234 ) -> Result<DeformationGradient, ConstitutiveError> {
235 let (matrix, vector) = bcs(applied_load);
236 match solver.root(
237 |deformation_gradient: &DeformationGradient| {
238 Ok(self.first_piola_kirchhoff_stress(deformation_gradient)?)
239 },
240 |deformation_gradient: &DeformationGradient| {
241 Ok(self.first_piola_kirchhoff_tangent_stiffness(deformation_gradient)?)
242 },
243 DeformationGradient::identity(),
244 EqualityConstraint::Linear(matrix, vector),
245 None,
246 ) {
247 Ok(deformation_gradient) => Ok(deformation_gradient),
248 Err(error) => Err(ConstitutiveError::Upstream(
249 format!("{error}"),
250 format!("{self:?}"),
251 )),
252 }
253 }
254}
255
256#[doc(hidden)]
257pub fn bcs(applied_load: AppliedLoad) -> (Matrix, Vector) {
258 match applied_load {
259 AppliedLoad::UniaxialStress(deformation_gradient_11) => {
260 let mut matrix = Matrix::zero(4, 9);
261 let mut vector = Vector::zero(4);
262 matrix[0][0] = 1.0;
263 matrix[1][1] = 1.0;
264 matrix[2][2] = 1.0;
265 matrix[3][5] = 1.0;
266 vector[0] = deformation_gradient_11;
267 (matrix, vector)
268 }
269 AppliedLoad::BiaxialStress(deformation_gradient_11, deformation_gradient_22) => {
270 let mut matrix = Matrix::zero(5, 9);
271 let mut vector = Vector::zero(5);
272 matrix[0][0] = 1.0;
273 matrix[1][1] = 1.0;
274 matrix[2][2] = 1.0;
275 matrix[3][5] = 1.0;
276 matrix[4][4] = 1.0;
277 vector[0] = deformation_gradient_11;
278 vector[4] = deformation_gradient_22;
279 (matrix, vector)
280 }
281 }
282}