1#[cfg(test)]
14pub mod test;
15
16use super::{super::fluid::viscous::Viscous, *};
17use crate::math::{
18 Matrix, Vector,
19 integrate::{ImplicitDaeFirstOrderRoot, ImplicitDaeZerothOrderRoot},
20 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
21};
22
23pub enum AppliedLoad<'a> {
25 UniaxialStress(fn(Scalar) -> Scalar, &'a [Scalar]),
27 BiaxialStress(fn(Scalar) -> Scalar, fn(Scalar) -> Scalar, &'a [Scalar]),
29}
30
31pub trait Viscoelastic
33where
34 Self: Solid + Viscous,
35{
36 fn cauchy_stress(
42 &self,
43 deformation_gradient: &DeformationGradient,
44 deformation_gradient_rate: &DeformationGradientRate,
45 ) -> Result<CauchyStress, ConstitutiveError> {
46 Ok(deformation_gradient
47 * self
48 .second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
49 * deformation_gradient.transpose()
50 / deformation_gradient.determinant())
51 }
52 fn cauchy_rate_tangent_stiffness(
58 &self,
59 deformation_gradient: &DeformationGradient,
60 deformation_gradient_rate: &DeformationGradientRate,
61 ) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
62 Ok(self
63 .second_piola_kirchhoff_rate_tangent_stiffness(
64 deformation_gradient,
65 deformation_gradient_rate,
66 )?
67 .contract_first_second_with_second(deformation_gradient, deformation_gradient)
68 / deformation_gradient.determinant())
69 }
70 fn first_piola_kirchhoff_stress(
76 &self,
77 deformation_gradient: &DeformationGradient,
78 deformation_gradient_rate: &DeformationGradientRate,
79 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
80 Ok(
81 self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
82 * deformation_gradient.inverse_transpose()
83 * deformation_gradient.determinant(),
84 )
85 }
86 fn first_piola_kirchhoff_rate_tangent_stiffness(
92 &self,
93 deformation_gradient: &DeformationGradient,
94 deformation_gradient_rate: &DeformationGradientRate,
95 ) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
96 Ok(self
97 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
98 .contract_second_with_first(&deformation_gradient.inverse_transpose())
99 * deformation_gradient.determinant())
100 }
101 fn second_piola_kirchhoff_stress(
107 &self,
108 deformation_gradient: &DeformationGradient,
109 deformation_gradient_rate: &DeformationGradientRate,
110 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
111 Ok(deformation_gradient.inverse()
112 * self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
113 * deformation_gradient.inverse_transpose()
114 * deformation_gradient.determinant())
115 }
116 fn second_piola_kirchhoff_rate_tangent_stiffness(
122 &self,
123 deformation_gradient: &DeformationGradient,
124 deformation_gradient_rate: &DeformationGradientRate,
125 ) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
126 let deformation_gradient_inverse = deformation_gradient.inverse();
127 Ok(self
128 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
129 .contract_first_second_with_second(
130 &deformation_gradient_inverse,
131 &deformation_gradient_inverse,
132 )
133 * deformation_gradient.determinant())
134 }
135}
136
137pub trait ZerothOrderRoot {
139 fn root(
145 &self,
146 applied_load: AppliedLoad,
147 integrator: impl ImplicitDaeZerothOrderRoot<DeformationGradient, DeformationGradients>,
148 solver: impl ZerothOrderRootFinding<DeformationGradient>,
149 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
150}
151
152pub trait FirstOrderRoot {
154 fn root(
160 &self,
161 applied_load: AppliedLoad,
162 integrator: impl ImplicitDaeFirstOrderRoot<
163 FirstPiolaKirchhoffStress,
164 FirstPiolaKirchhoffRateTangentStiffness,
165 DeformationGradientRate,
166 DeformationGradientRates,
167 >,
168 solver: impl FirstOrderRootFinding<
169 FirstPiolaKirchhoffStress,
170 FirstPiolaKirchhoffRateTangentStiffness,
171 DeformationGradientRate,
172 >,
173 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
174}
175
176impl<T> ZerothOrderRoot for T
177where
178 T: Viscoelastic,
179{
180 fn root(
181 &self,
182 applied_load: AppliedLoad,
183 integrator: impl ImplicitDaeZerothOrderRoot<DeformationGradient, DeformationGradients>,
184 solver: impl ZerothOrderRootFinding<DeformationGradientRate>,
185 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
186 match match applied_load {
187 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
188 let mut matrix = Matrix::zero(4, 9);
189 let mut vector = Vector::zero(4);
190 matrix[0][0] = 1.0;
191 matrix[1][1] = 1.0;
192 matrix[2][2] = 1.0;
193 matrix[3][5] = 1.0;
194 integrator.integrate(
195 |_: Scalar,
196 deformation_gradient: &DeformationGradient,
197 deformation_gradient_rate: &DeformationGradientRate| {
198 Ok(self.first_piola_kirchhoff_stress(
199 deformation_gradient,
200 deformation_gradient_rate,
201 )?)
202 },
203 solver,
204 time,
205 DeformationGradient::identity(),
206 |t: Scalar| {
207 vector[0] = deformation_gradient_rate_11(t);
208 EqualityConstraint::Linear(matrix.clone(), vector.clone())
209 },
210 )
211 }
212 AppliedLoad::BiaxialStress(
213 deformation_gradient_rate_11,
214 deformation_gradient_rate_22,
215 time,
216 ) => {
217 let mut matrix = Matrix::zero(5, 9);
218 let mut vector = Vector::zero(5);
219 matrix[0][0] = 1.0;
220 matrix[1][1] = 1.0;
221 matrix[2][2] = 1.0;
222 matrix[3][5] = 1.0;
223 matrix[4][4] = 1.0;
224 integrator.integrate(
225 |_: Scalar,
226 deformation_gradient: &DeformationGradient,
227 deformation_gradient_rate: &DeformationGradientRate| {
228 Ok(self.first_piola_kirchhoff_stress(
229 deformation_gradient,
230 deformation_gradient_rate,
231 )?)
232 },
233 solver,
234 time,
235 DeformationGradient::identity(),
236 |t: Scalar| {
237 vector[0] = deformation_gradient_rate_11(t);
238 vector[4] = deformation_gradient_rate_22(t);
239 EqualityConstraint::Linear(matrix.clone(), vector.clone())
240 },
241 )
242 }
243 } {
244 Ok(results) => Ok(results),
245 Err(error) => Err(ConstitutiveError::Upstream(
246 format!("{error}"),
247 format!("{self:?}"),
248 )),
249 }
250 }
251}
252
253impl<T> FirstOrderRoot for T
254where
255 T: Viscoelastic,
256{
257 fn root(
258 &self,
259 applied_load: AppliedLoad,
260 integrator: impl ImplicitDaeFirstOrderRoot<
261 FirstPiolaKirchhoffStress,
262 FirstPiolaKirchhoffRateTangentStiffness,
263 DeformationGradientRate,
264 DeformationGradientRates,
265 >,
266 solver: impl FirstOrderRootFinding<
267 FirstPiolaKirchhoffStress,
268 FirstPiolaKirchhoffRateTangentStiffness,
269 DeformationGradientRate,
270 >,
271 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
272 match match applied_load {
273 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
274 let mut matrix = Matrix::zero(4, 9);
275 let mut vector = Vector::zero(4);
276 matrix[0][0] = 1.0;
277 matrix[1][1] = 1.0;
278 matrix[2][2] = 1.0;
279 matrix[3][5] = 1.0;
280 integrator.integrate(
281 |_: Scalar,
282 deformation_gradient: &DeformationGradient,
283 deformation_gradient_rate: &DeformationGradientRate| {
284 Ok(self.first_piola_kirchhoff_stress(
285 deformation_gradient,
286 deformation_gradient_rate,
287 )?)
288 },
289 |_: Scalar,
290 deformation_gradient: &DeformationGradient,
291 deformation_gradient_rate: &DeformationGradientRate| {
292 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
293 deformation_gradient,
294 deformation_gradient_rate,
295 )?)
296 },
297 solver,
298 time,
299 DeformationGradient::identity(),
300 |t: Scalar| {
301 vector[0] = deformation_gradient_rate_11(t);
302 EqualityConstraint::Linear(matrix.clone(), vector.clone())
303 },
304 )
305 }
306 AppliedLoad::BiaxialStress(
307 deformation_gradient_rate_11,
308 deformation_gradient_rate_22,
309 time,
310 ) => {
311 let mut matrix = Matrix::zero(5, 9);
312 let mut vector = Vector::zero(5);
313 matrix[0][0] = 1.0;
314 matrix[1][1] = 1.0;
315 matrix[2][2] = 1.0;
316 matrix[3][5] = 1.0;
317 matrix[4][4] = 1.0;
318 integrator.integrate(
319 |_: Scalar,
320 deformation_gradient: &DeformationGradient,
321 deformation_gradient_rate: &DeformationGradientRate| {
322 Ok(self.first_piola_kirchhoff_stress(
323 deformation_gradient,
324 deformation_gradient_rate,
325 )?)
326 },
327 |_: Scalar,
328 deformation_gradient: &DeformationGradient,
329 deformation_gradient_rate: &DeformationGradientRate| {
330 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
331 deformation_gradient,
332 deformation_gradient_rate,
333 )?)
334 },
335 solver,
336 time,
337 DeformationGradient::identity(),
338 |t: Scalar| {
339 vector[0] = deformation_gradient_rate_11(t);
340 vector[4] = deformation_gradient_rate_22(t);
341 EqualityConstraint::Linear(matrix.clone(), vector.clone())
342 },
343 )
344 }
345 } {
346 Ok(results) => Ok(results),
347 Err(error) => Err(ConstitutiveError::Upstream(
348 format!("{error}"),
349 format!("{self:?}"),
350 )),
351 }
352 }
353}