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