1#[cfg(test)]
14pub mod test;
15
16use super::{super::fluid::viscous::Viscous, *};
17use crate::{
18 math::{
19 Matrix, Quantity, Vector,
20 integrate::{ImplicitDaeFirstOrderRoot, ImplicitDaeZerothOrderRoot},
21 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
22 },
23 units::Time,
24};
25
26pub enum AppliedLoad<'a> {
28 UniaxialStress(fn(Quantity<Time>) -> Scalar, &'a [Quantity<Time>]),
30 BiaxialStress(
32 fn(Quantity<Time>) -> Scalar,
33 fn(Quantity<Time>) -> Scalar,
34 &'a [Quantity<Time>],
35 ),
36}
37
38pub trait Viscoelastic
40where
41 Self: Solid + Viscous,
42{
43 fn cauchy_stress(
49 &self,
50 deformation_gradient: &DeformationGradient,
51 deformation_gradient_rate: &DeformationGradientRate,
52 ) -> Result<CauchyStress, ConstitutiveError> {
53 Ok(deformation_gradient
54 * self
55 .second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
56 * deformation_gradient.transpose()
57 / deformation_gradient.determinant())
58 }
59 fn cauchy_rate_tangent_stiffness(
65 &self,
66 deformation_gradient: &DeformationGradient,
67 deformation_gradient_rate: &DeformationGradientRate,
68 ) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
69 Ok(self
70 .second_piola_kirchhoff_rate_tangent_stiffness(
71 deformation_gradient,
72 deformation_gradient_rate,
73 )?
74 .contract_first_second_with_second(deformation_gradient, deformation_gradient)
75 / deformation_gradient.determinant())
76 }
77 fn first_piola_kirchhoff_stress(
83 &self,
84 deformation_gradient: &DeformationGradient,
85 deformation_gradient_rate: &DeformationGradientRate,
86 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
87 Ok(
88 self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
89 * deformation_gradient.inverse_transpose()
90 * deformation_gradient.determinant(),
91 )
92 }
93 fn first_piola_kirchhoff_rate_tangent_stiffness(
99 &self,
100 deformation_gradient: &DeformationGradient,
101 deformation_gradient_rate: &DeformationGradientRate,
102 ) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
103 Ok(self
104 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
105 .contract_second_with_first(&deformation_gradient.inverse_transpose())
106 * deformation_gradient.determinant())
107 }
108 fn second_piola_kirchhoff_stress(
114 &self,
115 deformation_gradient: &DeformationGradient,
116 deformation_gradient_rate: &DeformationGradientRate,
117 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
118 Ok(deformation_gradient.inverse()
119 * self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
120 * deformation_gradient.inverse_transpose()
121 * deformation_gradient.determinant())
122 }
123 fn second_piola_kirchhoff_rate_tangent_stiffness(
129 &self,
130 deformation_gradient: &DeformationGradient,
131 deformation_gradient_rate: &DeformationGradientRate,
132 ) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
133 let deformation_gradient_inverse = deformation_gradient.inverse();
134 Ok(self
135 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
136 .contract_first_second_with_second(
137 &deformation_gradient_inverse,
138 &deformation_gradient_inverse,
139 )
140 * deformation_gradient.determinant())
141 }
142}
143
144pub trait ZerothOrderRoot {
146 fn root(
152 &self,
153 applied_load: AppliedLoad,
154 integrator: impl ImplicitDaeZerothOrderRoot<
155 FirstPiolaKirchhoffStress,
156 DeformationGradient,
157 DeformationGradients,
158 DeformationGradientRates,
159 >,
160 solver: impl ZerothOrderRootFinding<FirstPiolaKirchhoffStress, DeformationGradientRate>,
161 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
162}
163
164pub trait FirstOrderRoot {
166 fn root(
172 &self,
173 applied_load: AppliedLoad,
174 integrator: impl ImplicitDaeFirstOrderRoot<
175 FirstPiolaKirchhoffStress,
176 FirstPiolaKirchhoffRateTangentStiffness,
177 DeformationGradient,
178 DeformationGradients,
179 DeformationGradientRates,
180 >,
181 solver: impl FirstOrderRootFinding<
182 FirstPiolaKirchhoffStress,
183 FirstPiolaKirchhoffRateTangentStiffness,
184 DeformationGradientRate,
185 >,
186 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
187}
188
189impl<T> ZerothOrderRoot for T
190where
191 T: Viscoelastic,
192{
193 fn root(
194 &self,
195 applied_load: AppliedLoad,
196 integrator: impl ImplicitDaeZerothOrderRoot<
197 FirstPiolaKirchhoffStress,
198 DeformationGradient,
199 DeformationGradients,
200 DeformationGradientRates,
201 >,
202 solver: impl ZerothOrderRootFinding<FirstPiolaKirchhoffStress, DeformationGradientRate>,
203 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
204 match match applied_load {
205 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
206 let mut matrix = Matrix::zero(4, 9);
207 let mut vector = Vector::zero(4);
208 matrix[0][0] = 1.0;
209 matrix[1][1] = 1.0;
210 matrix[2][2] = 1.0;
211 matrix[3][5] = 1.0;
212 integrator.integrate(
213 |_: Quantity<Time>,
214 deformation_gradient: &DeformationGradient,
215 deformation_gradient_rate: &DeformationGradientRate| {
216 Ok(self.first_piola_kirchhoff_stress(
217 deformation_gradient,
218 deformation_gradient_rate,
219 )?)
220 },
221 solver,
222 time,
223 DeformationGradient::identity(),
224 |t: Quantity<Time>| {
225 vector[0] = deformation_gradient_rate_11(t);
226 EqualityConstraint::Linear(matrix.clone(), vector.clone())
227 },
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 |_: Quantity<Time>,
244 deformation_gradient: &DeformationGradient,
245 deformation_gradient_rate: &DeformationGradientRate| {
246 Ok(self.first_piola_kirchhoff_stress(
247 deformation_gradient,
248 deformation_gradient_rate,
249 )?)
250 },
251 solver,
252 time,
253 DeformationGradient::identity(),
254 |t: Quantity<Time>| {
255 vector[0] = deformation_gradient_rate_11(t);
256 vector[4] = deformation_gradient_rate_22(t);
257 EqualityConstraint::Linear(matrix.clone(), vector.clone())
258 },
259 )
260 }
261 } {
262 Ok(results) => Ok(results),
263 Err(error) => Err(ConstitutiveError::Upstream(
264 format!("{error}"),
265 format!("{self:?}"),
266 )),
267 }
268 }
269}
270
271impl<T> FirstOrderRoot for T
272where
273 T: Viscoelastic,
274{
275 fn root(
276 &self,
277 applied_load: AppliedLoad,
278 integrator: impl ImplicitDaeFirstOrderRoot<
279 FirstPiolaKirchhoffStress,
280 FirstPiolaKirchhoffRateTangentStiffness,
281 DeformationGradient,
282 DeformationGradients,
283 DeformationGradientRates,
284 >,
285 solver: impl FirstOrderRootFinding<
286 FirstPiolaKirchhoffStress,
287 FirstPiolaKirchhoffRateTangentStiffness,
288 DeformationGradientRate,
289 >,
290 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
291 match match applied_load {
292 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
293 let mut matrix = Matrix::zero(4, 9);
294 let mut vector = Vector::zero(4);
295 matrix[0][0] = 1.0;
296 matrix[1][1] = 1.0;
297 matrix[2][2] = 1.0;
298 matrix[3][5] = 1.0;
299 integrator.integrate(
300 |_: Quantity<Time>,
301 deformation_gradient: &DeformationGradient,
302 deformation_gradient_rate: &DeformationGradientRate| {
303 Ok(self.first_piola_kirchhoff_stress(
304 deformation_gradient,
305 deformation_gradient_rate,
306 )?)
307 },
308 |_: Quantity<Time>,
309 deformation_gradient: &DeformationGradient,
310 deformation_gradient_rate: &DeformationGradientRate| {
311 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
312 deformation_gradient,
313 deformation_gradient_rate,
314 )?)
315 },
316 solver,
317 time,
318 DeformationGradient::identity(),
319 |t: Quantity<Time>| {
320 vector[0] = deformation_gradient_rate_11(t);
321 EqualityConstraint::Linear(matrix.clone(), vector.clone())
322 },
323 )
324 }
325 AppliedLoad::BiaxialStress(
326 deformation_gradient_rate_11,
327 deformation_gradient_rate_22,
328 time,
329 ) => {
330 let mut matrix = Matrix::zero(5, 9);
331 let mut vector = Vector::zero(5);
332 matrix[0][0] = 1.0;
333 matrix[1][1] = 1.0;
334 matrix[2][2] = 1.0;
335 matrix[3][5] = 1.0;
336 matrix[4][4] = 1.0;
337 integrator.integrate(
338 |_: Quantity<Time>,
339 deformation_gradient: &DeformationGradient,
340 deformation_gradient_rate: &DeformationGradientRate| {
341 Ok(self.first_piola_kirchhoff_stress(
342 deformation_gradient,
343 deformation_gradient_rate,
344 )?)
345 },
346 |_: Quantity<Time>,
347 deformation_gradient: &DeformationGradient,
348 deformation_gradient_rate: &DeformationGradientRate| {
349 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
350 deformation_gradient,
351 deformation_gradient_rate,
352 )?)
353 },
354 solver,
355 time,
356 DeformationGradient::identity(),
357 |t: Quantity<Time>| {
358 vector[0] = deformation_gradient_rate_11(t);
359 vector[4] = deformation_gradient_rate_22(t);
360 EqualityConstraint::Linear(matrix.clone(), vector.clone())
361 },
362 )
363 }
364 } {
365 Ok(results) => Ok(results),
366 Err(error) => Err(ConstitutiveError::Upstream(
367 format!("{error}"),
368 format!("{self:?}"),
369 )),
370 }
371 }
372}