conspire/constitutive/fluid/viscoplastic/
mod.rs1#[cfg(feature = "autodiff")]
4pub mod autodiff;
5
6#[cfg(test)]
7mod test;
8
9use crate::{
10 constitutive::{ConstitutiveError, fluid::plastic::Plastic},
11 math::{
12 Derivative, Differentiable, IDENTITY_22, Intermediate, Quantity, Rank2, Scalar, Tensor,
13 TensorArray, TensorRank4, TensorTuple, TensorTupleVec,
14 },
15 mechanics::{
16 DeformationGradientPlastic, DeformationGradientRatePlastic, MandelStressElastic,
17 StretchingRatePlastic, StretchingRatePlasticTangent, StretchingRatePlasticTangentYield,
18 },
19 units::{Dissipation, Rate, Stress},
20};
21
22type IntermediateRank4 = TensorRank4<3, Intermediate, Intermediate, Intermediate, Intermediate>;
23
24pub type ViscoplasticStateVariables<Y> = TensorTuple<DeformationGradientPlastic, Y>;
26
27pub type ViscoplasticStateVariablesHistory<Y> = TensorTupleVec<DeformationGradientPlastic, Y>;
29
30pub type ViscoplasticEvolution<Y> = Derivative<ViscoplasticStateVariables<Y>>;
32
33pub type ViscoplasticAlgebraRate<Y = Quantity> = TensorTuple<StretchingRatePlastic, Derivative<Y>>;
37
38pub type ViscoplasticEvolutionHistory<Y> =
40 TensorTupleVec<DeformationGradientRatePlastic, Derivative<Y>>;
41
42pub trait Viscoplastic<Y>
44where
45 Self: Plastic,
46 Y: Differentiable + Tensor,
47{
48 fn initial_state(&self) -> ViscoplasticStateVariables<Y>;
50 fn plastic_evolution(
56 &self,
57 mandel_stress: MandelStressElastic,
58 state_variables: &ViscoplasticStateVariables<Y>,
59 ) -> Result<ViscoplasticEvolution<Y>, ConstitutiveError>;
60 fn plastic_stretching_rate(
66 &self,
67 deviatoric_mandel_stress: MandelStressElastic,
68 yield_stress: Quantity<Stress>,
69 ) -> Result<StretchingRatePlastic, ConstitutiveError> {
70 let magnitude = deviatoric_mandel_stress.norm();
71 if magnitude.is_zero() {
72 Ok(StretchingRatePlastic::zero())
73 } else {
74 let reference_flow_rate = self.reference_flow_rate();
75 Ok(deviatoric_mandel_stress
76 * (reference_flow_rate / magnitude
77 * (magnitude / yield_stress).powf(1.0 / self.rate_sensitivity())))
78 }
79 }
80 fn plastic_stretching_rate_tangent(
88 &self,
89 deviatoric_mandel_stress: &MandelStressElastic,
90 yield_stress: Quantity<Stress>,
91 ) -> Result<StretchingRatePlasticTangent, ConstitutiveError> {
92 let magnitude = deviatoric_mandel_stress.norm();
93 if magnitude.is_zero() {
94 Ok(StretchingRatePlasticTangent::zero())
95 } else {
96 let rate_sensitivity = self.rate_sensitivity();
97 let flow = self.reference_flow_rate() / magnitude
98 * (magnitude / yield_stress).powf(1.0 / rate_sensitivity);
99 let normal = deviatoric_mandel_stress / magnitude;
100 Ok(
101 IntermediateRank4::dyad_ik_jl(&IDENTITY_22, &IDENTITY_22) * flow
102 + IntermediateRank4::dyad_ij_kl(&normal, &normal)
103 * (flow * (1.0 / rate_sensitivity - 1.0)),
104 )
105 }
106 }
107 fn plastic_stretching_rate_tangent_yield(
114 &self,
115 deviatoric_mandel_stress: MandelStressElastic,
116 yield_stress: Quantity<Stress>,
117 ) -> Result<StretchingRatePlasticTangentYield, ConstitutiveError> {
118 Ok(
119 self.plastic_stretching_rate(deviatoric_mandel_stress, yield_stress)? / yield_stress
120 * (-1.0 / self.rate_sensitivity()),
121 )
122 }
123 fn dissipation_potential(
129 &self,
130 plastic_stretching_rate: StretchingRatePlastic,
131 yield_stress: Quantity<Stress>,
132 ) -> Result<Quantity<Dissipation>, ConstitutiveError> {
133 let rate_sensitivity = self.rate_sensitivity();
134 let reference_flow_rate = self.reference_flow_rate();
135 Ok(
136 reference_flow_rate * yield_stress / (1.0 + rate_sensitivity)
137 * (plastic_stretching_rate.norm() / reference_flow_rate)
138 .powf(1.0 + rate_sensitivity),
139 )
140 }
141 fn dual_dissipation_potential(
147 &self,
148 deviatoric_mandel_stress: MandelStressElastic,
149 yield_stress: Quantity<Stress>,
150 ) -> Result<Quantity<Dissipation>, ConstitutiveError> {
151 let rate_sensitivity = self.rate_sensitivity();
152 Ok(self.reference_flow_rate()
153 * yield_stress
154 * (rate_sensitivity / (1.0 + rate_sensitivity))
155 * (deviatoric_mandel_stress.norm() / yield_stress)
156 .powf((1.0 + rate_sensitivity) / rate_sensitivity))
157 }
158 fn rate_sensitivity(&self) -> Scalar;
160 fn reference_flow_rate(&self) -> Quantity<Rate>;
162}
163
164#[derive(Clone, Debug)]
166pub struct ViscoplasticFlow {
167 pub yield_stress: Quantity<Stress>,
169 pub hardening_slope: Quantity<Stress>,
171 pub rate_sensitivity: Scalar,
173 pub reference_flow_rate: Quantity<Rate>,
175}
176
177impl Plastic for ViscoplasticFlow {
178 fn initial_yield_stress(&self) -> Quantity<Stress> {
179 self.yield_stress
180 }
181 fn hardening_slope(&self) -> Quantity<Stress> {
182 self.hardening_slope
183 }
184}
185
186impl Viscoplastic<Quantity> for ViscoplasticFlow {
187 fn initial_state(&self) -> ViscoplasticStateVariables<Quantity> {
188 (DeformationGradientPlastic::identity(), Quantity::default()).into()
189 }
190 fn plastic_evolution(
191 &self,
192 mandel_stress: MandelStressElastic,
193 state_variables: &ViscoplasticStateVariables<Quantity>,
194 ) -> Result<ViscoplasticEvolution<Quantity>, ConstitutiveError> {
195 default_plastic_evolution(self, mandel_stress, state_variables)
196 }
197 fn rate_sensitivity(&self) -> Scalar {
198 self.rate_sensitivity
199 }
200 fn reference_flow_rate(&self) -> Quantity<Rate> {
201 self.reference_flow_rate
202 }
203}
204
205pub fn default_plastic_evolution<C>(
206 model: &C,
207 mandel_stress: MandelStressElastic,
208 state_variables: &ViscoplasticStateVariables<Quantity>,
209) -> Result<ViscoplasticEvolution<Quantity>, ConstitutiveError>
210where
211 C: Viscoplastic<Quantity>,
212{
213 let (deformation_gradient_p, &equivalent_plastic_strain) = state_variables.into();
214 let plastic_stretching_rate = model.plastic_stretching_rate(
215 mandel_stress.deviatoric(),
216 model.yield_stress(equivalent_plastic_strain)?,
217 )?;
218 let equivalent_plastic_strain_rate = plastic_stretching_rate.norm();
219 Ok((
220 plastic_stretching_rate * deformation_gradient_p,
221 equivalent_plastic_strain_rate,
222 )
223 .into())
224}