1#[cfg(test)]
45pub mod test;
46
47use super::{super::fluid::viscous::Viscous, *};
48use crate::math::{
49 Matrix, Vector,
50 integrate::Explicit,
51 optimize::{
52 EqualityConstraint, FirstOrderRootFinding, OptimizationError, ZerothOrderRootFinding,
53 },
54};
55
56pub enum AppliedLoad<'a> {
58 UniaxialStress(fn(Scalar) -> Scalar, &'a [Scalar]),
60 BiaxialStress(fn(Scalar) -> Scalar, fn(Scalar) -> Scalar, &'a [Scalar]),
62}
63
64pub trait Viscoelastic
66where
67 Self: Solid + Viscous,
68{
69 fn cauchy_stress(
75 &self,
76 deformation_gradient: &DeformationGradient,
77 deformation_gradient_rate: &DeformationGradientRate,
78 ) -> Result<CauchyStress, ConstitutiveError> {
79 Ok(deformation_gradient
80 * self
81 .second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
82 * deformation_gradient.transpose()
83 / deformation_gradient.determinant())
84 }
85 fn cauchy_rate_tangent_stiffness(
91 &self,
92 deformation_gradient: &DeformationGradient,
93 deformation_gradient_rate: &DeformationGradientRate,
94 ) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
95 Ok(self
96 .second_piola_kirchhoff_rate_tangent_stiffness(
97 deformation_gradient,
98 deformation_gradient_rate,
99 )?
100 .contract_first_second_indices_with_second_indices_of(
101 deformation_gradient,
102 deformation_gradient,
103 )
104 / deformation_gradient.determinant())
105 }
106 fn first_piola_kirchhoff_stress(
112 &self,
113 deformation_gradient: &DeformationGradient,
114 deformation_gradient_rate: &DeformationGradientRate,
115 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
116 Ok(
117 self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
118 * deformation_gradient.inverse_transpose()
119 * deformation_gradient.determinant(),
120 )
121 }
122 fn first_piola_kirchhoff_rate_tangent_stiffness(
128 &self,
129 deformation_gradient: &DeformationGradient,
130 deformation_gradient_rate: &DeformationGradientRate,
131 ) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
132 Ok(self
133 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
134 .contract_second_index_with_first_index_of(&deformation_gradient.inverse_transpose())
135 * deformation_gradient.determinant())
136 }
137 fn second_piola_kirchhoff_stress(
143 &self,
144 deformation_gradient: &DeformationGradient,
145 deformation_gradient_rate: &DeformationGradientRate,
146 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
147 Ok(deformation_gradient.inverse()
148 * self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
149 * deformation_gradient.inverse_transpose()
150 * deformation_gradient.determinant())
151 }
152 fn second_piola_kirchhoff_rate_tangent_stiffness(
158 &self,
159 deformation_gradient: &DeformationGradient,
160 deformation_gradient_rate: &DeformationGradientRate,
161 ) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
162 let deformation_gradient_inverse = deformation_gradient.inverse();
163 Ok(self
164 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
165 .contract_first_second_indices_with_second_indices_of(
166 &deformation_gradient_inverse,
167 &deformation_gradient_inverse,
168 )
169 * deformation_gradient.determinant())
170 }
171}
172
173pub trait ZerothOrderRoot {
175 fn root(
181 &self,
182 applied_load: AppliedLoad,
183 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
184 solver: impl ZerothOrderRootFinding<DeformationGradient>,
185 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
186 #[doc(hidden)]
187 fn root_inner_0(
188 &self,
189 deformation_gradient: &DeformationGradient,
190 equality_constraint: EqualityConstraint,
191 solver: &impl ZerothOrderRootFinding<DeformationGradient>,
192 initial_guess: &DeformationGradientRate,
193 ) -> Result<DeformationGradientRate, OptimizationError>;
194}
195
196pub trait FirstOrderRoot {
198 fn root(
204 &self,
205 applied_load: AppliedLoad,
206 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
207 solver: impl FirstOrderRootFinding<
208 FirstPiolaKirchhoffStress,
209 FirstPiolaKirchhoffRateTangentStiffness,
210 DeformationGradientRate,
211 >,
212 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
213 #[doc(hidden)]
214 fn root_inner_1(
215 &self,
216 deformation_gradient: &DeformationGradient,
217 equality_constraint: EqualityConstraint,
218 solver: &impl FirstOrderRootFinding<
219 FirstPiolaKirchhoffStress,
220 FirstPiolaKirchhoffRateTangentStiffness,
221 DeformationGradientRate,
222 >,
223 initial_guess: &DeformationGradientRate,
224 ) -> Result<DeformationGradientRate, OptimizationError>;
225}
226
227impl<T> ZerothOrderRoot for T
228where
229 T: Viscoelastic,
230{
231 fn root(
232 &self,
233 applied_load: AppliedLoad,
234 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
235 solver: impl ZerothOrderRootFinding<DeformationGradientRate>,
236 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
237 let mut solution = DeformationGradientRate::zero();
238 match match applied_load {
239 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
240 let mut matrix = Matrix::zero(4, 9);
241 let mut vector = Vector::zero(4);
242 matrix[0][0] = 1.0;
243 matrix[1][1] = 1.0;
244 matrix[2][2] = 1.0;
245 matrix[3][5] = 1.0;
246 integrator.integrate(
247 |t: Scalar, deformation_gradient: &DeformationGradient| {
248 vector[0] = deformation_gradient_rate_11(t);
249 solution = self.root_inner_0(
250 deformation_gradient,
251 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
252 &solver,
253 &solution,
254 )?;
255 Ok(solution.clone())
256 },
257 time,
258 DeformationGradient::identity(),
259 )
260 }
261 AppliedLoad::BiaxialStress(
262 deformation_gradient_rate_11,
263 deformation_gradient_rate_22,
264 time,
265 ) => {
266 let mut matrix = Matrix::zero(5, 9);
267 let mut vector = Vector::zero(5);
268 matrix[0][0] = 1.0;
269 matrix[1][1] = 1.0;
270 matrix[2][2] = 1.0;
271 matrix[3][5] = 1.0;
272 matrix[4][4] = 1.0;
273 integrator.integrate(
274 |t: Scalar, deformation_gradient: &DeformationGradient| {
275 vector[0] = deformation_gradient_rate_11(t);
276 vector[4] = deformation_gradient_rate_22(t);
277 solution = self.root_inner_0(
278 deformation_gradient,
279 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
280 &solver,
281 &solution,
282 )?;
283 Ok(solution.clone())
284 },
285 time,
286 DeformationGradient::identity(),
287 )
288 }
289 } {
290 Ok(results) => Ok(results),
291 Err(error) => Err(ConstitutiveError::Upstream(
292 format!("{error}"),
293 format!("{self:?}"),
294 )),
295 }
296 }
297 fn root_inner_0(
298 &self,
299 deformation_gradient: &DeformationGradient,
300 equality_constraint: EqualityConstraint,
301 solver: &impl ZerothOrderRootFinding<DeformationGradientRate>,
302 initial_guess: &DeformationGradientRate,
303 ) -> Result<DeformationGradientRate, OptimizationError> {
304 solver.root(
305 |deformation_gradient_rate: &DeformationGradientRate| {
306 Ok(self.first_piola_kirchhoff_stress(
307 deformation_gradient,
308 deformation_gradient_rate,
309 )?)
310 },
311 initial_guess.clone(),
312 equality_constraint,
313 )
314 }
315}
316
317impl<T> FirstOrderRoot for T
318where
319 T: Viscoelastic,
320{
321 fn root(
322 &self,
323 applied_load: AppliedLoad,
324 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
325 solver: impl FirstOrderRootFinding<
326 FirstPiolaKirchhoffStress,
327 FirstPiolaKirchhoffRateTangentStiffness,
328 DeformationGradientRate,
329 >,
330 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
331 let mut solution = DeformationGradientRate::zero();
332 match match applied_load {
333 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
334 let mut matrix = Matrix::zero(4, 9);
335 let mut vector = Vector::zero(4);
336 matrix[0][0] = 1.0;
337 matrix[1][1] = 1.0;
338 matrix[2][2] = 1.0;
339 matrix[3][5] = 1.0;
340 integrator.integrate(
341 |t: Scalar, deformation_gradient: &DeformationGradient| {
342 vector[0] = deformation_gradient_rate_11(t);
343 solution = self.root_inner_1(
344 deformation_gradient,
345 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
346 &solver,
347 &solution,
348 )?;
349 Ok(solution.clone())
350 },
351 time,
352 DeformationGradient::identity(),
353 )
354 }
355 AppliedLoad::BiaxialStress(
356 deformation_gradient_rate_11,
357 deformation_gradient_rate_22,
358 time,
359 ) => {
360 let mut matrix = Matrix::zero(5, 9);
361 let mut vector = Vector::zero(5);
362 matrix[0][0] = 1.0;
363 matrix[1][1] = 1.0;
364 matrix[2][2] = 1.0;
365 matrix[3][5] = 1.0;
366 matrix[4][4] = 1.0;
367 integrator.integrate(
368 |t: Scalar, deformation_gradient: &DeformationGradient| {
369 vector[0] = deformation_gradient_rate_11(t);
370 vector[4] = deformation_gradient_rate_22(t);
371 solution = self.root_inner_1(
372 deformation_gradient,
373 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
374 &solver,
375 &solution,
376 )?;
377 Ok(solution.clone())
378 },
379 time,
380 DeformationGradient::identity(),
381 )
382 }
383 } {
384 Ok(results) => Ok(results),
385 Err(error) => Err(ConstitutiveError::Upstream(
386 format!("{error}"),
387 format!("{self:?}"),
388 )),
389 }
390 }
391 fn root_inner_1(
392 &self,
393 deformation_gradient: &DeformationGradient,
394 equality_constraint: EqualityConstraint,
395 solver: &impl FirstOrderRootFinding<
396 FirstPiolaKirchhoffStress,
397 FirstPiolaKirchhoffRateTangentStiffness,
398 DeformationGradientRate,
399 >,
400 initial_guess: &DeformationGradientRate,
401 ) -> Result<DeformationGradientRate, OptimizationError> {
402 solver.root(
403 |deformation_gradient_rate: &DeformationGradientRate| {
404 Ok(self.first_piola_kirchhoff_stress(
405 deformation_gradient,
406 deformation_gradient_rate,
407 )?)
408 },
409 |deformation_gradient_rate: &DeformationGradientRate| {
410 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
411 deformation_gradient,
412 deformation_gradient_rate,
413 )?)
414 },
415 initial_guess.clone(),
416 equality_constraint,
417 )
418 }
419}