1use crate::{
4 constitutive::{
5 ConstitutiveError,
6 solid::{Solid, elastic::AppliedLoad},
7 },
8 math::{
9 ContractFirstSecondIndicesWithSecondIndicesOf, ContractSecondIndexWithFirstIndexOf,
10 IDENTITY, Matrix, Rank2, Tensor, TensorArray, TensorTuple, Vector,
11 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
12 },
13 mechanics::{
14 CauchyStress, CauchyTangentStiffness, DeformationGradient, FirstPiolaKirchhoffStress,
15 FirstPiolaKirchhoffTangentStiffness, SecondPiolaKirchhoffStress,
16 SecondPiolaKirchhoffTangentStiffness,
17 },
18};
19
20pub trait ElasticIV<V, T1, T2, T3>
22where
23 Self: Solid,
24{
25 fn cauchy_stress_foo(
31 &self,
32 deformation_gradient: &DeformationGradient,
33 internal_variables: &V,
34 ) -> Result<CauchyStress, ConstitutiveError> {
35 Ok(deformation_gradient
36 * self.second_piola_kirchhoff_stress_foo(deformation_gradient, internal_variables)?
37 * deformation_gradient.transpose()
38 / deformation_gradient.determinant())
39 }
40 fn cauchy_tangent_stiffness_foo(
46 &self,
47 deformation_gradient: &DeformationGradient,
48 internal_variables: &V,
49 ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
50 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
51 let cauchy_stress = self.cauchy_stress_foo(deformation_gradient, internal_variables)?;
52 let some_stress = &cauchy_stress * &deformation_gradient_inverse_transpose;
53 Ok(self
54 .second_piola_kirchhoff_tangent_stiffness_foo(deformation_gradient, internal_variables)?
55 .contract_first_second_indices_with_second_indices_of(
56 deformation_gradient,
57 deformation_gradient,
58 )
59 / deformation_gradient.determinant()
60 - CauchyTangentStiffness::dyad_ij_kl(
61 &cauchy_stress,
62 &deformation_gradient_inverse_transpose,
63 )
64 + CauchyTangentStiffness::dyad_il_kj(&some_stress, &IDENTITY)
65 + CauchyTangentStiffness::dyad_ik_jl(&IDENTITY, &some_stress))
66 }
67 fn first_piola_kirchhoff_stress_foo(
73 &self,
74 deformation_gradient: &DeformationGradient,
75 internal_variables: &V,
76 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
77 Ok(
78 self.cauchy_stress_foo(deformation_gradient, internal_variables)?
79 * deformation_gradient.inverse_transpose()
80 * deformation_gradient.determinant(),
81 )
82 }
83 fn first_piola_kirchhoff_tangent_stiffness_foo(
89 &self,
90 deformation_gradient: &DeformationGradient,
91 internal_variables: &V,
92 ) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
93 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
94 let first_piola_kirchhoff_stress =
95 self.first_piola_kirchhoff_stress_foo(deformation_gradient, internal_variables)?;
96 Ok(self
97 .cauchy_tangent_stiffness_foo(deformation_gradient, internal_variables)?
98 .contract_second_index_with_first_index_of(&deformation_gradient_inverse_transpose)
99 * deformation_gradient.determinant()
100 + FirstPiolaKirchhoffTangentStiffness::dyad_ij_kl(
101 &first_piola_kirchhoff_stress,
102 &deformation_gradient_inverse_transpose,
103 )
104 - FirstPiolaKirchhoffTangentStiffness::dyad_il_kj(
105 &first_piola_kirchhoff_stress,
106 &deformation_gradient_inverse_transpose,
107 ))
108 }
109 fn second_piola_kirchhoff_stress_foo(
115 &self,
116 deformation_gradient: &DeformationGradient,
117 internal_variables: &V,
118 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
119 Ok(deformation_gradient.inverse()
120 * self.first_piola_kirchhoff_stress_foo(deformation_gradient, internal_variables)?)
121 }
122 fn second_piola_kirchhoff_tangent_stiffness_foo(
128 &self,
129 deformation_gradient: &DeformationGradient,
130 internal_variables: &V,
131 ) -> Result<SecondPiolaKirchhoffTangentStiffness, ConstitutiveError> {
132 let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
133 let deformation_gradient_inverse = deformation_gradient_inverse_transpose.transpose();
134 let second_piola_kirchhoff_stress =
135 self.second_piola_kirchhoff_stress_foo(deformation_gradient, internal_variables)?;
136 Ok(self
137 .cauchy_tangent_stiffness_foo(deformation_gradient, internal_variables)?
138 .contract_first_second_indices_with_second_indices_of(
139 &deformation_gradient_inverse,
140 &deformation_gradient_inverse,
141 )
142 * deformation_gradient.determinant()
143 + SecondPiolaKirchhoffTangentStiffness::dyad_ij_kl(
144 &second_piola_kirchhoff_stress,
145 &deformation_gradient_inverse_transpose,
146 )
147 - SecondPiolaKirchhoffTangentStiffness::dyad_il_kj(
148 &second_piola_kirchhoff_stress,
149 &deformation_gradient_inverse_transpose,
150 )
151 - SecondPiolaKirchhoffTangentStiffness::dyad_ik_jl(
152 &deformation_gradient_inverse,
153 &second_piola_kirchhoff_stress,
154 ))
155 }
156 fn internal_variables_initial(&self) -> V;
158 fn internal_variables_residual(
160 &self,
161 deformation_gradient: &DeformationGradient,
162 internal_variables: &V,
163 ) -> Result<V, ConstitutiveError>;
164 fn internal_variables_tangents(
166 &self,
167 deformation_gradient: &DeformationGradient,
168 internal_variables: &V,
169 ) -> Result<(T1, T2, T3), ConstitutiveError>;
170 fn internal_variables_constraints(&self) -> (&[usize], usize);
172}
173
174pub trait ZerothOrderRoot<V, T1, T2, T3>
176where
177 V: Tensor,
178{
179 type Variables;
181 fn root(
187 &self,
188 applied_load: AppliedLoad,
189 solver: impl ZerothOrderRootFinding<Self::Variables>,
190 ) -> Result<(DeformationGradient, V), ConstitutiveError>;
191}
192
193pub trait FirstOrderRoot<V, T1, T2, T3>
195where
196 T1: Tensor,
197 T2: Tensor,
198 T3: Tensor,
199 V: Tensor,
200{
201 type Variables;
203 fn root(
209 &self,
210 applied_load: AppliedLoad,
211 solver: impl FirstOrderRootFinding<
212 Self::Variables,
213 TensorTuple<FirstPiolaKirchhoffTangentStiffness, TensorTuple<T1, TensorTuple<T2, T3>>>,
214 Self::Variables,
215 >,
216 ) -> Result<(DeformationGradient, V), ConstitutiveError>;
217}
218
219impl<T, V, T1, T2, T3> ZerothOrderRoot<V, T1, T2, T3> for T
220where
221 T: ElasticIV<V, T1, T2, T3>,
222 V: Tensor,
223{
224 type Variables = TensorTuple<DeformationGradient, V>;
225 fn root(
226 &self,
227 applied_load: AppliedLoad,
228 solver: impl ZerothOrderRootFinding<Self::Variables>,
229 ) -> Result<(DeformationGradient, V), ConstitutiveError> {
230 let (extra_constraints, num_vars) = self.internal_variables_constraints();
231 let (matrix, vector) = match applied_load {
232 AppliedLoad::UniaxialStress(deformation_gradient_11) => {
233 let num_constraints = 4;
234 let num_constraints_vars = extra_constraints.len();
235 let mut matrix = Matrix::zero(num_constraints + num_constraints_vars, 9 + num_vars);
236 let mut vector = Vector::zero(num_constraints + num_constraints_vars);
237 matrix[0][0] = 1.0;
238 matrix[1][1] = 1.0;
239 matrix[2][2] = 1.0;
240 matrix[3][5] = 1.0;
241 let mut i = num_constraints;
242 extra_constraints.iter().for_each(|&j| {
243 matrix[i][j] = 1.0;
244 i += 1;
245 });
246 vector[0] = deformation_gradient_11;
247 (matrix, vector)
248 }
249 AppliedLoad::BiaxialStress(_, _) => {
250 todo!()
251 }
252 };
253 match solver.root(
254 |variables: &Self::Variables| {
255 let (deformation_gradient, internal_variables) = variables.into();
256 Ok(TensorTuple::from((
257 self.first_piola_kirchhoff_stress_foo(
258 deformation_gradient,
259 internal_variables,
260 )?,
261 self.internal_variables_residual(deformation_gradient, internal_variables)?,
262 )))
263 },
264 Self::Variables::from((
265 DeformationGradient::identity(),
266 self.internal_variables_initial(),
267 )),
268 EqualityConstraint::Linear(matrix, vector),
269 ) {
270 Ok(solution) => Ok(solution.into()),
271 Err(error) => Err(ConstitutiveError::Upstream(
272 format!("{error}"),
273 format!("{self:?}"),
274 )),
275 }
276 }
277}
278
279impl<T, V, T1, T2, T3> FirstOrderRoot<V, T1, T2, T3> for T
280where
281 T1: Tensor,
282 T2: Tensor,
283 T3: Tensor,
284 T: ElasticIV<V, T1, T2, T3>,
285 V: Tensor,
286{
287 type Variables = TensorTuple<DeformationGradient, V>;
288 fn root(
289 &self,
290 applied_load: AppliedLoad,
291 solver: impl FirstOrderRootFinding<
292 Self::Variables,
293 TensorTuple<FirstPiolaKirchhoffTangentStiffness, TensorTuple<T1, TensorTuple<T2, T3>>>,
294 Self::Variables,
295 >,
296 ) -> Result<(DeformationGradient, V), ConstitutiveError> {
297 let (extra_constraints, num_vars) = self.internal_variables_constraints();
298 let (matrix, vector) = match applied_load {
299 AppliedLoad::UniaxialStress(deformation_gradient_11) => {
300 let num_constraints = 4;
301 let num_constraints_vars = extra_constraints.len();
302 let mut matrix = Matrix::zero(num_constraints + num_constraints_vars, 9 + num_vars);
303 let mut vector = Vector::zero(num_constraints + num_constraints_vars);
304 matrix[0][0] = 1.0;
305 matrix[1][1] = 1.0;
306 matrix[2][2] = 1.0;
307 matrix[3][5] = 1.0;
308 let mut i = num_constraints;
309 extra_constraints.iter().for_each(|&j| {
310 matrix[i][j] = 1.0;
311 i += 1;
312 });
313 vector[0] = deformation_gradient_11;
314 (matrix, vector)
315 }
316 AppliedLoad::BiaxialStress(_, _) => {
317 todo!()
318 }
319 };
320 match solver.root(
321 |variables: &Self::Variables| {
322 let (deformation_gradient, internal_variables) = variables.into();
323 Ok(TensorTuple::from((
324 self.first_piola_kirchhoff_stress_foo(
325 deformation_gradient,
326 internal_variables,
327 )?,
328 self.internal_variables_residual(deformation_gradient, internal_variables)?,
329 )))
330 },
331 |variables: &Self::Variables| {
332 let (deformation_gradient, internal_variables) = variables.into();
333 let tangent_0 = self.first_piola_kirchhoff_tangent_stiffness_foo(
334 deformation_gradient,
335 internal_variables,
336 )?;
337 let (tangent_1, tangent_2, tangent_3) =
338 self.internal_variables_tangents(deformation_gradient, internal_variables)?;
339 Ok((tangent_0, (tangent_1, (tangent_2, tangent_3).into()).into()).into())
340 },
341 Self::Variables::from((
342 DeformationGradient::identity(),
343 self.internal_variables_initial(),
344 )),
345 EqualityConstraint::Linear(matrix, vector),
346 ) {
347 Ok(solution) => Ok(solution.into()),
348 Err(error) => Err(ConstitutiveError::Upstream(
349 format!("{error}"),
350 format!("{self:?}"),
351 )),
352 }
353 }
354}