conspire/constitutive/hybrid/elastic/multiplicative/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 constitutive::{
6 ConstitutiveError,
7 hybrid::{Multiplicative, MultiplicativeTrait},
8 solid::{
9 Solid,
10 elastic::{Elastic, internal_variables::ElasticIV},
11 },
12 },
13 math::{
14 ContractThirdIndexWithFirstIndexOf, IDENTITY_10, Rank2, TensorArray, TensorRank2,
15 TensorRank4,
16 optimize::{EqualityConstraint, GradientDescent, ZerothOrderRootFinding},
17 },
18 mechanics::{
19 CauchyStress, CauchyTangentStiffness, CauchyTangentStiffness1, DeformationGradient,
20 DeformationGradient2, FirstPiolaKirchhoffStress, FirstPiolaKirchhoffStress1,
21 FirstPiolaKirchhoffStress2, FirstPiolaKirchhoffTangentStiffness,
22 FirstPiolaKirchhoffTangentStiffness2, Scalar, SecondPiolaKirchhoffStress,
23 SecondPiolaKirchhoffTangentStiffness,
24 },
25};
26
27impl<C1, C2> Solid for Multiplicative<C1, C2>
28where
29 C1: Solid,
32 C2: Clone + std::fmt::Debug,
33{
34 fn bulk_modulus(&self) -> Scalar {
35 todo!() }
37 fn shear_modulus(&self) -> Scalar {
38 todo!() }
40}
41
42impl<C1, C2>
43 ElasticIV<
44 DeformationGradient2,
45 TensorRank4<3, 2, 0, 1, 0>,
46 TensorRank4<3, 1, 0, 2, 0>,
47 FirstPiolaKirchhoffTangentStiffness2,
48 > for Multiplicative<C1, C2>
49where
50 C1: Elastic,
51 C2: Elastic,
52{
53 fn cauchy_stress_foo(
59 &self,
60 deformation_gradient: &DeformationGradient,
61 deformation_gradient_2: &DeformationGradient2,
62 ) -> Result<CauchyStress, ConstitutiveError> {
63 let (deformation_gradient_2_inverse, jacobian_2) =
64 deformation_gradient_2.inverse_and_determinant();
65 let deformation_gradient_1 = deformation_gradient * &deformation_gradient_2_inverse;
66 Ok(self.0.cauchy_stress(&deformation_gradient_1.into())? / jacobian_2)
67 }
68 fn cauchy_tangent_stiffness_foo(
74 &self,
75 deformation_gradient: &DeformationGradient,
76 deformation_gradient_2: &DeformationGradient2,
77 ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
78 let (deformation_gradient_2_inverse, jacobian_2) =
79 deformation_gradient_2.inverse_and_determinant();
80 let deformation_gradient_1 = deformation_gradient * &deformation_gradient_2_inverse;
81 Ok(CauchyTangentStiffness1::from(
82 self.0
83 .cauchy_tangent_stiffness(&deformation_gradient_1.into())?,
84 ) * (deformation_gradient_2_inverse.transpose() / jacobian_2))
85 }
86 fn first_piola_kirchhoff_stress_foo(
92 &self,
93 deformation_gradient: &DeformationGradient,
94 deformation_gradient_2: &DeformationGradient2,
95 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
96 Ok(
97 self.cauchy_stress_foo(deformation_gradient, deformation_gradient_2)?
98 * deformation_gradient.inverse_transpose()
99 * deformation_gradient.determinant(),
100 )
101 }
102 fn second_piola_kirchhoff_stress_foo(
108 &self,
109 deformation_gradient: &DeformationGradient,
110 deformation_gradient_2: &DeformationGradient2,
111 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
112 Ok(deformation_gradient.inverse()
113 * self
114 .first_piola_kirchhoff_stress_foo(deformation_gradient, deformation_gradient_2)?)
115 }
116 fn internal_variables_initial(&self) -> DeformationGradient2 {
117 DeformationGradient2::identity()
118 }
119 fn internal_variables_residual(
125 &self,
126 deformation_gradient: &DeformationGradient,
127 deformation_gradient_2: &DeformationGradient2,
128 ) -> Result<DeformationGradient2, ConstitutiveError> {
129 let deformation_gradient_2_inverse = deformation_gradient_2.inverse();
130 let deformation_gradient_1 = deformation_gradient * &deformation_gradient_2_inverse;
131 Ok(FirstPiolaKirchhoffStress2::from(
132 self.1
133 .first_piola_kirchhoff_stress(deformation_gradient_2.into())?,
134 ) - deformation_gradient_1.transpose()
135 * FirstPiolaKirchhoffStress1::from(
136 self.0
137 .first_piola_kirchhoff_stress(&deformation_gradient_1.into())?,
138 )
139 * deformation_gradient_2_inverse.transpose())
140 }
141 fn internal_variables_tangents(
153 &self,
154 deformation_gradient: &DeformationGradient,
155 deformation_gradient_2: &DeformationGradient2,
156 ) -> Result<
157 (
158 TensorRank4<3, 2, 0, 1, 0>,
159 TensorRank4<3, 1, 0, 2, 0>,
160 FirstPiolaKirchhoffTangentStiffness2,
161 ),
162 ConstitutiveError,
163 > {
164 let deformation_gradient_2_inverse = deformation_gradient_2.inverse();
169 let deformation_gradient_2_inverse_transpose = deformation_gradient_2_inverse.transpose();
170 let deformation_gradient_1 = deformation_gradient * &deformation_gradient_2_inverse;
171 let deformation_gradient_1_transpose = deformation_gradient_1.transpose();
172 let first_piola_kirchhoff_stress =
173 self.first_piola_kirchhoff_stress_foo(deformation_gradient, deformation_gradient_2)?;
174 let tangent_0 = self.first_piola_kirchhoff_tangent_stiffness_foo(
175 deformation_gradient,
176 deformation_gradient_2,
177 )?;
178 let tangent_1 = TensorRank4::dyad_il_kj(
179 &(deformation_gradient_2_inverse_transpose * -1.0),
180 &first_piola_kirchhoff_stress,
181 ) - &deformation_gradient_1_transpose * &tangent_0;
182 let tangent_2 = TensorRank4::dyad_il_jk(
183 &first_piola_kirchhoff_stress,
184 &(&deformation_gradient_2_inverse * -1.0),
185 ) - tangent_0
186 .contract_third_index_with_first_index_of(&deformation_gradient_1);
187 let tangent_3 = FirstPiolaKirchhoffTangentStiffness2::from(
188 self.1
189 .first_piola_kirchhoff_tangent_stiffness(deformation_gradient_2.into())?,
190 ) - tangent_1
191 .contract_third_index_with_first_index_of(&deformation_gradient_1)
192 + TensorRank4::dyad_il_jk(
193 &(deformation_gradient_1_transpose * first_piola_kirchhoff_stress),
194 &deformation_gradient_2_inverse,
195 );
196 Ok((tangent_1, tangent_2, tangent_3))
197 }
198 fn internal_variables_constraints(&self) -> (&[usize], usize) {
199 (&[10, 11, 14], 9)
200 }
201}
202
203impl<C1, C2> Elastic for Multiplicative<C1, C2>
204where
205 C1: Elastic,
206 C2: Elastic,
207{
208 fn cauchy_stress(
214 &self,
215 deformation_gradient: &DeformationGradient,
216 ) -> Result<CauchyStress, ConstitutiveError> {
217 let (deformation_gradient_1, deformation_gradient_2) =
218 self.deformation_gradients(deformation_gradient)?;
219 Ok(self.0.cauchy_stress(&deformation_gradient_1)? / deformation_gradient_2.determinant())
220 }
221 fn cauchy_tangent_stiffness(
223 &self,
224 _: &DeformationGradient,
225 ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
226 panic!()
227 }
228 fn first_piola_kirchhoff_stress(
234 &self,
235 deformation_gradient: &DeformationGradient,
236 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
237 let (deformation_gradient_1, deformation_gradient_2) =
238 self.deformation_gradients(deformation_gradient)?;
239 let deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0> =
240 deformation_gradient_2.inverse_transpose().into();
241 Ok(self
242 .0
243 .first_piola_kirchhoff_stress(&deformation_gradient_1)?
244 * deformation_gradient_2_inverse_transpose)
245 }
246 fn first_piola_kirchhoff_tangent_stiffness(
248 &self,
249 _: &DeformationGradient,
250 ) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
251 panic!()
252 }
253 fn second_piola_kirchhoff_stress(
259 &self,
260 deformation_gradient: &DeformationGradient,
261 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
262 let (deformation_gradient_1, deformation_gradient_2) =
263 self.deformation_gradients(deformation_gradient)?;
264 let deformation_gradient_2_inverse: TensorRank2<3, 0, 0> =
265 deformation_gradient_2.inverse().into();
266 Ok(&deformation_gradient_2_inverse
267 * self
268 .0
269 .second_piola_kirchhoff_stress(&deformation_gradient_1)?
270 * deformation_gradient_2_inverse.transpose())
271 }
272 fn second_piola_kirchhoff_tangent_stiffness(
274 &self,
275 _: &DeformationGradient,
276 ) -> Result<SecondPiolaKirchhoffTangentStiffness, ConstitutiveError> {
277 panic!()
278 }
279}
280
281impl<C1, C2> MultiplicativeTrait for Multiplicative<C1, C2>
282where
283 C1: Elastic,
284 C2: Elastic,
285{
286 fn deformation_gradients(
287 &self,
288 deformation_gradient: &DeformationGradient,
289 ) -> Result<(DeformationGradient, DeformationGradient), ConstitutiveError> {
290 if deformation_gradient.is_identity() {
291 Ok((IDENTITY_10, IDENTITY_10))
292 } else {
293 match GradientDescent::default().root(
294 |deformation_gradient_2: &DeformationGradient| {
295 let deformation_gradient_1: DeformationGradient =
296 (deformation_gradient * deformation_gradient_2.inverse()).into();
297 let deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0> =
298 deformation_gradient_2.inverse_transpose().into();
299 let right_hand_side: FirstPiolaKirchhoffStress = (deformation_gradient_1
300 .transpose()
301 * self
302 .0
303 .first_piola_kirchhoff_stress(&deformation_gradient_1)?
304 * deformation_gradient_2_inverse_transpose)
305 .into();
306 Ok(self
307 .1
308 .first_piola_kirchhoff_stress(deformation_gradient_2)?
309 - right_hand_side)
310 },
311 IDENTITY_10,
312 EqualityConstraint::None,
313 ) {
314 Ok(deformation_gradient_2) => {
315 let deformation_gradient_1 =
316 (deformation_gradient * deformation_gradient_2.inverse()).into();
317 Ok((deformation_gradient_1, deformation_gradient_2))
318 }
319 Err(error) => Err(ConstitutiveError::Upstream(
320 format!("{error}"),
321 format!("{self:?}"),
322 )),
323 }
324 }
325 }
326}