1#![doc = include_str!("doc.md")]
6
7#[cfg(feature = "doc")]
8pub mod doc;
9
10#[cfg(test)]
11pub mod test;
12
13use super::{super::fluid::viscous::Viscous, *};
14use crate::{
15 math::{
16 Matrix, Quantity, Vector,
17 integrate::{ImplicitDaeFirstOrderRoot, ImplicitDaeZerothOrderRoot},
18 optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
19 },
20 units::Time,
21};
22
23pub enum AppliedLoad<'a> {
25 UniaxialStress(fn(Quantity<Time>) -> Scalar, &'a [Quantity<Time>]),
27 BiaxialStress(
29 fn(Quantity<Time>) -> Scalar,
30 fn(Quantity<Time>) -> Scalar,
31 &'a [Quantity<Time>],
32 ),
33}
34
35pub trait Viscoelastic
37where
38 Self: Solid + Viscous,
39{
40 fn cauchy_stress(
46 &self,
47 deformation_gradient: &DeformationGradient,
48 deformation_gradient_rate: &DeformationGradientRate,
49 ) -> Result<CauchyStress, ConstitutiveError> {
50 Ok(deformation_gradient
51 * self
52 .second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
53 * deformation_gradient.transpose()
54 / deformation_gradient.determinant())
55 }
56 fn cauchy_rate_tangent_stiffness(
62 &self,
63 deformation_gradient: &DeformationGradient,
64 deformation_gradient_rate: &DeformationGradientRate,
65 ) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
66 Ok(self
67 .second_piola_kirchhoff_rate_tangent_stiffness(
68 deformation_gradient,
69 deformation_gradient_rate,
70 )?
71 .contract_first_second_with_second(deformation_gradient, deformation_gradient)
72 / deformation_gradient.determinant())
73 }
74 fn first_piola_kirchhoff_stress(
80 &self,
81 deformation_gradient: &DeformationGradient,
82 deformation_gradient_rate: &DeformationGradientRate,
83 ) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
84 Ok(
85 self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
86 * deformation_gradient.inverse_transpose()
87 * deformation_gradient.determinant(),
88 )
89 }
90 fn first_piola_kirchhoff_rate_tangent_stiffness(
96 &self,
97 deformation_gradient: &DeformationGradient,
98 deformation_gradient_rate: &DeformationGradientRate,
99 ) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
100 Ok(self
101 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
102 .contract_second_with_first(&deformation_gradient.inverse_transpose())
103 * deformation_gradient.determinant())
104 }
105 fn second_piola_kirchhoff_stress(
111 &self,
112 deformation_gradient: &DeformationGradient,
113 deformation_gradient_rate: &DeformationGradientRate,
114 ) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
115 Ok(deformation_gradient.inverse()
116 * self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
117 * deformation_gradient.inverse_transpose()
118 * deformation_gradient.determinant())
119 }
120 fn second_piola_kirchhoff_rate_tangent_stiffness(
126 &self,
127 deformation_gradient: &DeformationGradient,
128 deformation_gradient_rate: &DeformationGradientRate,
129 ) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
130 let deformation_gradient_inverse = deformation_gradient.inverse();
131 Ok(self
132 .cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
133 .contract_first_second_with_second(
134 &deformation_gradient_inverse,
135 &deformation_gradient_inverse,
136 )
137 * deformation_gradient.determinant())
138 }
139}
140
141pub trait ZerothOrderRoot {
143 fn root(
149 &self,
150 applied_load: AppliedLoad,
151 integrator: impl ImplicitDaeZerothOrderRoot<
152 FirstPiolaKirchhoffStress,
153 DeformationGradient,
154 DeformationGradients,
155 DeformationGradientRates,
156 >,
157 solver: impl ZerothOrderRootFinding<FirstPiolaKirchhoffStress, DeformationGradientRate>,
158 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
159}
160
161pub trait FirstOrderRoot {
163 fn root(
169 &self,
170 applied_load: AppliedLoad,
171 integrator: impl ImplicitDaeFirstOrderRoot<
172 FirstPiolaKirchhoffStress,
173 FirstPiolaKirchhoffRateTangentStiffness,
174 DeformationGradient,
175 DeformationGradients,
176 DeformationGradientRates,
177 >,
178 solver: impl FirstOrderRootFinding<
179 FirstPiolaKirchhoffStress,
180 FirstPiolaKirchhoffRateTangentStiffness,
181 DeformationGradientRate,
182 >,
183 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
184}
185
186impl<T> ZerothOrderRoot for T
187where
188 T: Viscoelastic,
189{
190 fn root(
191 &self,
192 applied_load: AppliedLoad,
193 integrator: impl ImplicitDaeZerothOrderRoot<
194 FirstPiolaKirchhoffStress,
195 DeformationGradient,
196 DeformationGradients,
197 DeformationGradientRates,
198 >,
199 solver: impl ZerothOrderRootFinding<FirstPiolaKirchhoffStress, DeformationGradientRate>,
200 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
201 match applied_load {
202 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
203 let mut matrix = Matrix::zero(4, 9);
204 let mut vector = Vector::zero(4);
205 matrix[0][0] = 1.0;
206 matrix[1][1] = 1.0;
207 matrix[2][2] = 1.0;
208 matrix[3][5] = 1.0;
209 integrator.integrate(
210 |_: Quantity<Time>,
211 deformation_gradient: &DeformationGradient,
212 deformation_gradient_rate: &DeformationGradientRate| {
213 Ok(self.first_piola_kirchhoff_stress(
214 deformation_gradient,
215 deformation_gradient_rate,
216 )?)
217 },
218 solver,
219 time,
220 DeformationGradient::identity(),
221 |t: Quantity<Time>| {
222 vector[0] = deformation_gradient_rate_11(t);
223 EqualityConstraint::Linear(matrix.clone(), vector.clone())
224 },
225 )
226 }
227 AppliedLoad::BiaxialStress(
228 deformation_gradient_rate_11,
229 deformation_gradient_rate_22,
230 time,
231 ) => {
232 let mut matrix = Matrix::zero(5, 9);
233 let mut vector = Vector::zero(5);
234 matrix[0][0] = 1.0;
235 matrix[1][1] = 1.0;
236 matrix[2][2] = 1.0;
237 matrix[3][5] = 1.0;
238 matrix[4][4] = 1.0;
239 integrator.integrate(
240 |_: Quantity<Time>,
241 deformation_gradient: &DeformationGradient,
242 deformation_gradient_rate: &DeformationGradientRate| {
243 Ok(self.first_piola_kirchhoff_stress(
244 deformation_gradient,
245 deformation_gradient_rate,
246 )?)
247 },
248 solver,
249 time,
250 DeformationGradient::identity(),
251 |t: Quantity<Time>| {
252 vector[0] = deformation_gradient_rate_11(t);
253 vector[4] = deformation_gradient_rate_22(t);
254 EqualityConstraint::Linear(matrix.clone(), vector.clone())
255 },
256 )
257 }
258 }
259 .map_err(|error| ConstitutiveError::upstream(error, self))
260 }
261}
262
263impl<T> FirstOrderRoot for T
264where
265 T: Viscoelastic,
266{
267 fn root(
268 &self,
269 applied_load: AppliedLoad,
270 integrator: impl ImplicitDaeFirstOrderRoot<
271 FirstPiolaKirchhoffStress,
272 FirstPiolaKirchhoffRateTangentStiffness,
273 DeformationGradient,
274 DeformationGradients,
275 DeformationGradientRates,
276 >,
277 solver: impl FirstOrderRootFinding<
278 FirstPiolaKirchhoffStress,
279 FirstPiolaKirchhoffRateTangentStiffness,
280 DeformationGradientRate,
281 >,
282 ) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
283 match applied_load {
284 AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
285 let mut matrix = Matrix::zero(4, 9);
286 let mut vector = Vector::zero(4);
287 matrix[0][0] = 1.0;
288 matrix[1][1] = 1.0;
289 matrix[2][2] = 1.0;
290 matrix[3][5] = 1.0;
291 integrator.integrate(
292 |_: Quantity<Time>,
293 deformation_gradient: &DeformationGradient,
294 deformation_gradient_rate: &DeformationGradientRate| {
295 Ok(self.first_piola_kirchhoff_stress(
296 deformation_gradient,
297 deformation_gradient_rate,
298 )?)
299 },
300 |_: Quantity<Time>,
301 deformation_gradient: &DeformationGradient,
302 deformation_gradient_rate: &DeformationGradientRate| {
303 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
304 deformation_gradient,
305 deformation_gradient_rate,
306 )?)
307 },
308 solver,
309 time,
310 DeformationGradient::identity(),
311 |t: Quantity<Time>| {
312 vector[0] = deformation_gradient_rate_11(t);
313 EqualityConstraint::Linear(matrix.clone(), vector.clone())
314 },
315 )
316 }
317 AppliedLoad::BiaxialStress(
318 deformation_gradient_rate_11,
319 deformation_gradient_rate_22,
320 time,
321 ) => {
322 let mut matrix = Matrix::zero(5, 9);
323 let mut vector = Vector::zero(5);
324 matrix[0][0] = 1.0;
325 matrix[1][1] = 1.0;
326 matrix[2][2] = 1.0;
327 matrix[3][5] = 1.0;
328 matrix[4][4] = 1.0;
329 integrator.integrate(
330 |_: Quantity<Time>,
331 deformation_gradient: &DeformationGradient,
332 deformation_gradient_rate: &DeformationGradientRate| {
333 Ok(self.first_piola_kirchhoff_stress(
334 deformation_gradient,
335 deformation_gradient_rate,
336 )?)
337 },
338 |_: Quantity<Time>,
339 deformation_gradient: &DeformationGradient,
340 deformation_gradient_rate: &DeformationGradientRate| {
341 Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
342 deformation_gradient,
343 deformation_gradient_rate,
344 )?)
345 },
346 solver,
347 time,
348 DeformationGradient::identity(),
349 |t: Quantity<Time>| {
350 vector[0] = deformation_gradient_rate_11(t);
351 vector[4] = deformation_gradient_rate_22(t);
352 EqualityConstraint::Linear(matrix.clone(), vector.clone())
353 },
354 )
355 }
356 }
357 .map_err(|error| ConstitutiveError::upstream(error, self))
358 }
359}