conspire/constitutive/solid/hyperelastic/arruda_boyce/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 constitutive::{
6 Constitutive, ConstitutiveError, Parameters,
7 solid::{FIVE_THIRDS, Solid, TWO_THIRDS, elastic::Elastic, hyperelastic::Hyperelastic},
8 },
9 math::{
10 IDENTITY, Rank2,
11 special::{inverse_langevin, langevin_derivative},
12 },
13 mechanics::{CauchyStress, CauchyTangentStiffness, Deformation, DeformationGradient, Scalar},
14};
15
16#[doc = include_str!("doc.md")]
17#[derive(Debug)]
18pub struct ArrudaBoyce<P> {
19 parameters: P,
20}
21
22impl<P> ArrudaBoyce<P>
23where
24 P: Parameters,
25{
26 pub fn number_of_links(&self) -> &Scalar {
28 self.parameters.get(2)
29 }
30}
31
32impl<P> Constitutive<P> for ArrudaBoyce<P>
33where
34 P: Parameters,
35{
36 fn new(parameters: P) -> Self {
37 Self { parameters }
38 }
39}
40
41impl<P> Solid for ArrudaBoyce<P>
42where
43 P: Parameters,
44{
45 fn bulk_modulus(&self) -> &Scalar {
46 self.parameters.get(0)
47 }
48 fn shear_modulus(&self) -> &Scalar {
49 self.parameters.get(1)
50 }
51}
52
53impl<P> Elastic for ArrudaBoyce<P>
54where
55 P: Parameters,
56{
57 #[doc = include_str!("cauchy_stress.md")]
58 fn cauchy_stress(
59 &self,
60 deformation_gradient: &DeformationGradient,
61 ) -> Result<CauchyStress, ConstitutiveError> {
62 let jacobian = self.jacobian(deformation_gradient)?;
63 let (
64 deviatoric_isochoric_left_cauchy_green_deformation,
65 isochoric_left_cauchy_green_deformation_trace,
66 ) = (deformation_gradient.left_cauchy_green() / jacobian.powf(TWO_THIRDS))
67 .deviatoric_and_trace();
68 let gamma =
69 (isochoric_left_cauchy_green_deformation_trace / 3.0 / self.number_of_links()).sqrt();
70 if gamma >= 1.0 {
71 Err(ConstitutiveError::Custom(
72 "Maximum extensibility reached.".to_string(),
73 deformation_gradient.clone(),
74 format!("{:?}", &self),
75 ))
76 } else {
77 let gamma_0 = (1.0 / self.number_of_links()).sqrt();
78 Ok(deviatoric_isochoric_left_cauchy_green_deformation
79 * (self.shear_modulus() * inverse_langevin(gamma) / inverse_langevin(gamma_0)
80 * gamma_0
81 / gamma
82 / jacobian)
83 + IDENTITY * self.bulk_modulus() * 0.5 * (jacobian - 1.0 / jacobian))
84 }
85 }
86 #[doc = include_str!("cauchy_tangent_stiffness.md")]
87 fn cauchy_tangent_stiffness(
88 &self,
89 deformation_gradient: &DeformationGradient,
90 ) -> Result<CauchyTangentStiffness, ConstitutiveError> {
91 let jacobian = self.jacobian(deformation_gradient)?;
92 let inverse_transpose_deformation_gradient = deformation_gradient.inverse_transpose();
93 let left_cauchy_green_deformation = deformation_gradient.left_cauchy_green();
94 let deviatoric_left_cauchy_green_deformation = left_cauchy_green_deformation.deviatoric();
95 let (
96 deviatoric_isochoric_left_cauchy_green_deformation,
97 isochoric_left_cauchy_green_deformation_trace,
98 ) = (left_cauchy_green_deformation / jacobian.powf(TWO_THIRDS)).deviatoric_and_trace();
99 let gamma =
100 (isochoric_left_cauchy_green_deformation_trace / 3.0 / self.number_of_links()).sqrt();
101 if gamma >= 1.0 {
102 Err(ConstitutiveError::Custom(
103 "Maximum extensibility reached.".to_string(),
104 deformation_gradient.clone(),
105 format!("{:?}", &self),
106 ))
107 } else {
108 let gamma_0 = (1.0 / self.number_of_links()).sqrt();
109 let eta = inverse_langevin(gamma);
110 let scaled_shear_modulus =
111 gamma_0 / inverse_langevin(gamma_0) * self.shear_modulus() * eta
112 / gamma
113 / jacobian.powf(FIVE_THIRDS);
114 let scaled_deviatoric_isochoric_left_cauchy_green_deformation =
115 deviatoric_left_cauchy_green_deformation * scaled_shear_modulus;
116 let term = CauchyTangentStiffness::dyad_ij_kl(
117 &scaled_deviatoric_isochoric_left_cauchy_green_deformation,
118 &(deviatoric_isochoric_left_cauchy_green_deformation
119 * &inverse_transpose_deformation_gradient
120 * ((1.0 / eta / langevin_derivative(eta) - 1.0 / gamma)
121 / 3.0
122 / self.number_of_links()
123 / gamma)),
124 );
125 Ok(
126 (CauchyTangentStiffness::dyad_ik_jl(&IDENTITY, deformation_gradient)
127 + CauchyTangentStiffness::dyad_il_jk(deformation_gradient, &IDENTITY)
128 - CauchyTangentStiffness::dyad_ij_kl(&IDENTITY, deformation_gradient)
129 * (TWO_THIRDS))
130 * scaled_shear_modulus
131 + CauchyTangentStiffness::dyad_ij_kl(
132 &(IDENTITY * (0.5 * self.bulk_modulus() * (jacobian + 1.0 / jacobian))
133 - scaled_deviatoric_isochoric_left_cauchy_green_deformation
134 * (FIVE_THIRDS)),
135 &inverse_transpose_deformation_gradient,
136 )
137 + term,
138 )
139 }
140 }
141}
142
143impl<P> Hyperelastic for ArrudaBoyce<P>
144where
145 P: Parameters,
146{
147 #[doc = include_str!("helmholtz_free_energy_density.md")]
148 fn helmholtz_free_energy_density(
149 &self,
150 deformation_gradient: &DeformationGradient,
151 ) -> Result<Scalar, ConstitutiveError> {
152 let jacobian = self.jacobian(deformation_gradient)?;
153 let isochoric_left_cauchy_green_deformation =
154 deformation_gradient.left_cauchy_green() / jacobian.powf(TWO_THIRDS);
155 let gamma =
156 (isochoric_left_cauchy_green_deformation.trace() / 3.0 / self.number_of_links()).sqrt();
157 if gamma >= 1.0 {
158 Err(ConstitutiveError::Custom(
159 "Maximum extensibility reached.".to_string(),
160 deformation_gradient.clone(),
161 format!("{:?}", &self),
162 ))
163 } else {
164 let eta = inverse_langevin(gamma);
165 let gamma_0 = (1.0 / self.number_of_links()).sqrt();
166 let eta_0 = inverse_langevin(gamma_0);
167 Ok(3.0 * gamma_0 / eta_0
168 * self.shear_modulus()
169 * self.number_of_links()
170 * (gamma * eta
171 - gamma_0 * eta_0
172 - (eta_0 * eta.sinh() / (eta * eta_0.sinh())).ln())
173 + 0.5 * self.bulk_modulus() * (0.5 * (jacobian.powi(2) - 1.0) - jacobian.ln()))
174 }
175 }
176}