1#[cfg(test)]
14pub mod test;
15
16use super::{super::fluid::viscous::Viscous, *};
17use crate::math::{
18 Matrix, TensorVec, Vector,
19 integrate::Explicit,
20 optimize::{
21 EqualityConstraint, FirstOrderRootFinding, OptimizationError, ZerothOrderRootFinding,
22 },
23};
24
25pub enum AppliedLoad<'a> {
27 UniaxialStress(fn(Scalar) -> Scalar, &'a [Scalar]),
29 BiaxialStress(fn(Scalar) -> Scalar, fn(Scalar) -> Scalar, &'a [Scalar]),
31}
32
33pub trait Viscoelastic
35where
36 Self: Solid + Viscous,
37{
38 fn cauchy_stress(
44 &self,
45 deformation_gradient: &DeformationGradient,
46 deformation_gradient_rate: &DeformationGradientRate,
47 ) -> Result<CauchyStress, ConstitutiveError> {
48 Ok(deformation_gradient
49 * self
50 .second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
51 * deformation_gradient.transpose()
52 / deformation_gradient.determinant())
53 }
54 fn cauchy_rate_tangent_stiffness(
60 &self,
61 deformation_gradient: &DeformationGradient,
62 deformation_gradient_rate: &DeformationGradientRate,
63 ) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
64 Ok(self
65 .second_piola_kirchhoff_rate_tangent_stiffness(
66 deformation_gradient,
67 deformation_gradient_rate,
68 )?
69 .contract_first_second_indices_with_second_indices_of(
70 deformation_gradient,
71 deformation_gradient,
72 )
73 / deformation_gradient.determinant())
74 }
75 fn first_piola_kirchhoff_stress(
81 &self,
82 deformation_gradient: &DeformationGradient,
83 deformation_gradient_rate: &DeformationGradientRate,
84 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
85 Ok(
86 self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
87 * deformation_gradient.inverse_transpose()
88 * deformation_gradient.determinant(),
89 )
90 }
91 fn first_piola_kirchhoff_rate_tangent_stiffness(
97 &self,
98 deformation_gradient: &DeformationGradient,
99 deformation_gradient_rate: &DeformationGradientRate,
100 ) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
101 Ok(self
102 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
103 .contract_second_index_with_first_index_of(&deformation_gradient.inverse_transpose())
104 * deformation_gradient.determinant())
105 }
106 fn second_piola_kirchhoff_stress(
112 &self,
113 deformation_gradient: &DeformationGradient,
114 deformation_gradient_rate: &DeformationGradientRate,
115 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
116 Ok(deformation_gradient.inverse()
117 * self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
118 * deformation_gradient.inverse_transpose()
119 * deformation_gradient.determinant())
120 }
121 fn second_piola_kirchhoff_rate_tangent_stiffness(
127 &self,
128 deformation_gradient: &DeformationGradient,
129 deformation_gradient_rate: &DeformationGradientRate,
130 ) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
131 let deformation_gradient_inverse = deformation_gradient.inverse();
132 Ok(self
133 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
134 .contract_first_second_indices_with_second_indices_of(
135 &deformation_gradient_inverse,
136 &deformation_gradient_inverse,
137 )
138 * deformation_gradient.determinant())
139 }
140}
141
142pub trait ZerothOrderRoot {
144 fn root(
150 &self,
151 applied_load: AppliedLoad,
152 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
153 solver: impl ZerothOrderRootFinding<DeformationGradient>,
154 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
155 #[doc(hidden)]
156 fn root_inner_0(
157 &self,
158 deformation_gradient: &DeformationGradient,
159 equality_constraint: EqualityConstraint,
160 solver: &impl ZerothOrderRootFinding<DeformationGradient>,
161 initial_guess: &DeformationGradientRate,
162 ) -> Result<DeformationGradientRate, OptimizationError>;
163}
164
165pub trait FirstOrderRoot {
167 fn root(
173 &self,
174 applied_load: AppliedLoad,
175 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
176 solver: impl FirstOrderRootFinding<
177 FirstPiolaKirchhoffStress,
178 FirstPiolaKirchhoffTangentStiffness,
179 DeformationGradient,
180 >,
181 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
182 #[doc(hidden)]
183 fn root_inner_1(
184 &self,
185 deformation_gradient: &DeformationGradient,
186 equality_constraint: EqualityConstraint,
187 solver: &impl FirstOrderRootFinding<
188 FirstPiolaKirchhoffStress,
189 FirstPiolaKirchhoffTangentStiffness,
190 DeformationGradient,
191 >,
192 initial_guess: &DeformationGradientRate,
193 ) -> Result<DeformationGradientRate, OptimizationError>;
194}
195
196impl<T> ZerothOrderRoot for T
197where
198 T: Viscoelastic,
199{
200 fn root(
201 &self,
202 applied_load: AppliedLoad,
203 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
204 solver: impl ZerothOrderRootFinding<DeformationGradient>,
205 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
206 let mut solution = DeformationGradientRate::zero();
207 match match applied_load {
208 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
209 let mut matrix = Matrix::zero(4, 9);
210 let mut vector = Vector::zero(4);
211 matrix[0][0] = 1.0;
212 matrix[1][1] = 1.0;
213 matrix[2][2] = 1.0;
214 matrix[3][5] = 1.0;
215 integrator.integrate(
216 |t: Scalar, deformation_gradient: &DeformationGradient| {
217 vector[0] = deformation_gradient_rate_11(t);
218 solution = self.root_inner_0(
219 deformation_gradient,
220 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
221 &solver,
222 &solution,
223 )?;
224 Ok(solution.clone())
225 },
226 time,
227 DeformationGradient::identity(),
228 )
229 }
230 AppliedLoad::BiaxialStress(
231 deformation_gradient_rate_11,
232 deformation_gradient_rate_22,
233 time,
234 ) => {
235 let mut matrix = Matrix::zero(5, 9);
236 let mut vector = Vector::zero(5);
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 matrix[4][4] = 1.0;
242 integrator.integrate(
243 |t: Scalar, deformation_gradient: &DeformationGradient| {
244 vector[0] = deformation_gradient_rate_11(t);
245 vector[4] = deformation_gradient_rate_22(t);
246 solution = self.root_inner_0(
247 deformation_gradient,
248 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
249 &solver,
250 &solution,
251 )?;
252 Ok(solution.clone())
253 },
254 time,
255 DeformationGradient::identity(),
256 )
257 }
258 } {
259 Ok(deformation_gradient) => Ok(deformation_gradient),
260 Err(error) => Err(ConstitutiveError::Upstream(
261 format!("{error}"),
262 format!("{self:?}"),
263 )),
264 }
265 }
266 fn root_inner_0(
267 &self,
268 deformation_gradient: &DeformationGradient,
269 equality_constraint: EqualityConstraint,
270 solver: &impl ZerothOrderRootFinding<DeformationGradient>,
271 initial_guess: &DeformationGradientRate,
272 ) -> Result<DeformationGradientRate, OptimizationError> {
273 solver.root(
274 |deformation_gradient_rate: &DeformationGradientRate| {
275 Ok(self.first_piola_kirchhoff_stress(
276 deformation_gradient,
277 deformation_gradient_rate,
278 )?)
279 },
280 initial_guess.clone(),
281 equality_constraint,
282 )
283 }
284}
285
286impl<T> FirstOrderRoot for T
287where
288 T: Viscoelastic,
289{
290 fn root(
291 &self,
292 applied_load: AppliedLoad,
293 integrator: impl Explicit<DeformationGradientRate, DeformationGradientRates>,
294 solver: impl FirstOrderRootFinding<
295 FirstPiolaKirchhoffStress,
296 FirstPiolaKirchhoffTangentStiffness,
297 DeformationGradient,
298 >,
299 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
300 let mut solution = DeformationGradientRate::zero();
301 match match applied_load {
302 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
303 let mut matrix = Matrix::zero(4, 9);
304 let mut vector = Vector::zero(4);
305 matrix[0][0] = 1.0;
306 matrix[1][1] = 1.0;
307 matrix[2][2] = 1.0;
308 matrix[3][5] = 1.0;
309 integrator.integrate(
310 |t: Scalar, deformation_gradient: &DeformationGradient| {
311 vector[0] = deformation_gradient_rate_11(t);
312 solution = self.root_inner_1(
313 deformation_gradient,
314 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
315 &solver,
316 &solution,
317 )?;
318 Ok(solution.clone())
319 },
320 time,
321 DeformationGradient::identity(),
322 )
323 }
324 AppliedLoad::BiaxialStress(
325 deformation_gradient_rate_11,
326 deformation_gradient_rate_22,
327 time,
328 ) => {
329 let mut matrix = Matrix::zero(5, 9);
330 let mut vector = Vector::zero(5);
331 matrix[0][0] = 1.0;
332 matrix[1][1] = 1.0;
333 matrix[2][2] = 1.0;
334 matrix[3][5] = 1.0;
335 matrix[4][4] = 1.0;
336 integrator.integrate(
337 |t: Scalar, deformation_gradient: &DeformationGradient| {
338 vector[0] = deformation_gradient_rate_11(t);
339 vector[4] = deformation_gradient_rate_22(t);
340 solution = self.root_inner_1(
341 deformation_gradient,
342 EqualityConstraint::Linear(matrix.clone(), vector.clone()),
343 &solver,
344 &solution,
345 )?;
346 Ok(solution.clone())
347 },
348 time,
349 DeformationGradient::identity(),
350 )
351 }
352 } {
353 Ok(deformation_gradient) => Ok(deformation_gradient),
354 Err(error) => Err(ConstitutiveError::Upstream(
355 format!("{error}"),
356 format!("{self:?}"),
357 )),
358 }
359 }
360 fn root_inner_1(
361 &self,
362 deformation_gradient: &DeformationGradient,
363 equality_constraint: EqualityConstraint,
364 solver: &impl FirstOrderRootFinding<
365 FirstPiolaKirchhoffStress,
366 FirstPiolaKirchhoffTangentStiffness,
367 DeformationGradient,
368 >,
369 initial_guess: &DeformationGradientRate,
370 ) -> Result<DeformationGradientRate, OptimizationError> {
371 solver.root(
372 |deformation_gradient_rate: &DeformationGradientRate| {
373 Ok(self.first_piola_kirchhoff_stress(
374 deformation_gradient,
375 deformation_gradient_rate,
376 )?)
377 },
378 |deformation_gradient_rate: &DeformationGradientRate| {
379 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
380 deformation_gradient,
381 deformation_gradient_rate,
382 )?)
383 },
384 initial_guess.clone(),
385 equality_constraint,
386 )
387 }
388}