use crate::{
constitutive::{ConstitutiveError, fluid::plastic::Plastic},
math::{Rank2, Scalar, Tensor, TensorArray, TensorTuple, TensorTupleVec},
mechanics::{DeformationGradientPlastic, MandelStressElastic, StretchingRatePlastic},
};
pub type ViscoplasticStateVariables<Y> = TensorTuple<DeformationGradientPlastic, Y>;
pub type ViscoplasticStateVariablesHistory<Y> = TensorTupleVec<DeformationGradientPlastic, Y>;
pub trait Viscoplastic<Y>
where
Self: Plastic,
Y: Tensor,
{
fn initial_state(&self) -> ViscoplasticStateVariables<Y>;
fn plastic_evolution(
&self,
mandel_stress: MandelStressElastic,
state_variables: &ViscoplasticStateVariables<Y>,
) -> Result<ViscoplasticStateVariables<Y>, ConstitutiveError>;
fn plastic_stretching_rate(
&self,
deviatoric_mandel_stress: MandelStressElastic,
yield_stress: Scalar,
) -> Result<StretchingRatePlastic, ConstitutiveError> {
let magnitude = deviatoric_mandel_stress.norm();
if magnitude == 0.0 {
Ok(StretchingRatePlastic::zero())
} else {
Ok(deviatoric_mandel_stress
* (self.reference_flow_rate() / magnitude
* (magnitude / yield_stress).powf(1.0 / self.rate_sensitivity())))
}
}
fn rate_sensitivity(&self) -> Scalar;
fn reference_flow_rate(&self) -> Scalar;
}
#[derive(Clone, Debug)]
pub struct ViscoplasticFlow {
pub yield_stress: Scalar,
pub hardening_slope: Scalar,
pub rate_sensitivity: Scalar,
pub reference_flow_rate: Scalar,
}
impl Plastic for ViscoplasticFlow {
fn initial_yield_stress(&self) -> Scalar {
self.yield_stress
}
fn hardening_slope(&self) -> Scalar {
self.hardening_slope
}
}
impl Viscoplastic<Scalar> for ViscoplasticFlow {
fn initial_state(&self) -> ViscoplasticStateVariables<Scalar> {
(DeformationGradientPlastic::identity(), 0.0).into()
}
fn plastic_evolution(
&self,
mandel_stress: MandelStressElastic,
state_variables: &ViscoplasticStateVariables<Scalar>,
) -> Result<ViscoplasticStateVariables<Scalar>, ConstitutiveError> {
default_plastic_evolution(self, mandel_stress, state_variables)
}
fn rate_sensitivity(&self) -> Scalar {
self.rate_sensitivity
}
fn reference_flow_rate(&self) -> Scalar {
self.reference_flow_rate
}
}
pub fn default_plastic_evolution<C>(
model: &C,
mandel_stress: MandelStressElastic,
state_variables: &ViscoplasticStateVariables<Scalar>,
) -> Result<ViscoplasticStateVariables<Scalar>, ConstitutiveError>
where
C: Viscoplastic<Scalar>,
{
let (deformation_gradient_p, &equivalent_plastic_strain) = state_variables.into();
let plastic_stretching_rate = model.plastic_stretching_rate(
mandel_stress.deviatoric(),
model.yield_stress(equivalent_plastic_strain)?,
)?;
let equivalent_plastic_strain_rate = plastic_stretching_rate.norm();
Ok((
plastic_stretching_rate * deformation_gradient_p,
equivalent_plastic_strain_rate,
)
.into())
}