use crate::{
constitutive::{ConstitutiveError, fluid::plastic::Plastic, solid::Solid},
math::{
ContractFirstSecondWithSecond, ContractSecondWithFirst, IDENTITY, Matrix, Quantity, Rank2,
},
mechanics::{
CauchyStress, CauchyTangentStiffness, DeformationGradient, DeformationGradientPlastic,
FirstPiolaKirchhoffStress, FirstPiolaKirchhoffTangentStiffness, MandelStressElastic,
Scalar, SecondPiolaKirchhoffStress, SecondPiolaKirchhoffTangentStiffness,
},
units::Time,
};
pub enum AppliedLoad<'a> {
UniaxialStress(fn(Quantity<Time>) -> Scalar, &'a [Quantity<Time>]),
BiaxialStress(
fn(Quantity<Time>) -> Scalar,
fn(Quantity<Time>) -> Scalar,
&'a [Quantity<Time>],
),
}
type Prescribed = Vec<(usize, fn(Quantity<Time>) -> Scalar)>;
#[doc(hidden)]
pub fn bcs(applied_load: AppliedLoad<'_>) -> (Matrix, Prescribed, &'_ [Quantity<Time>]) {
let (mut matrix, prescribed, time) = match applied_load {
AppliedLoad::UniaxialStress(deformation_gradient_11, time) => {
(Matrix::zero(4, 9), vec![(0, deformation_gradient_11)], time)
}
AppliedLoad::BiaxialStress(deformation_gradient_11, deformation_gradient_22, time) => (
Matrix::zero(5, 9),
vec![(0, deformation_gradient_11), (4, deformation_gradient_22)],
time,
),
};
matrix[0][0] = 1.0;
matrix[1][1] = 1.0;
matrix[2][2] = 1.0;
matrix[3][5] = 1.0;
if matrix.len() == 5 {
matrix[4][4] = 1.0
}
(matrix, prescribed, time)
}
pub trait ElasticPlasticOrViscoplastic
where
Self: Solid + Plastic,
{
fn cauchy_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<CauchyStress, ConstitutiveError> {
Ok(deformation_gradient
* self.second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)?
* deformation_gradient.transpose()
/ deformation_gradient.determinant())
}
fn cauchy_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<CauchyTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
let cauchy_stress = self.cauchy_stress(deformation_gradient, deformation_gradient_p)?;
let some_stress = &cauchy_stress * &deformation_gradient_inverse_transpose;
Ok(self
.second_piola_kirchhoff_tangent_stiffness(deformation_gradient, deformation_gradient_p)?
.contract_first_second_with_second(deformation_gradient, deformation_gradient)
/ deformation_gradient.determinant()
- CauchyTangentStiffness::dyad_ij_kl(
&cauchy_stress,
&deformation_gradient_inverse_transpose,
)
+ CauchyTangentStiffness::dyad_il_kj(&some_stress, &IDENTITY)
+ CauchyTangentStiffness::dyad_ik_jl(&IDENTITY, &some_stress))
}
fn first_piola_kirchhoff_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
Ok(
self.cauchy_stress(deformation_gradient, deformation_gradient_p)?
* deformation_gradient.inverse_transpose()
* deformation_gradient.determinant(),
)
}
fn first_piola_kirchhoff_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
let first_piola_kirchhoff_stress =
self.first_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)?;
Ok(self
.cauchy_tangent_stiffness(deformation_gradient, deformation_gradient_p)?
.contract_second_with_first(&deformation_gradient_inverse_transpose)
* deformation_gradient.determinant()
+ FirstPiolaKirchhoffTangentStiffness::dyad_ij_kl(
&first_piola_kirchhoff_stress,
&deformation_gradient_inverse_transpose,
)
- FirstPiolaKirchhoffTangentStiffness::dyad_il_kj(
&first_piola_kirchhoff_stress,
&deformation_gradient_inverse_transpose,
))
}
fn mandel_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<MandelStressElastic, ConstitutiveError> {
let jacobian = self.jacobian(deformation_gradient)?;
let deformation_gradient_e = deformation_gradient * deformation_gradient_p.inverse();
let cauchy_stress = self.cauchy_stress(deformation_gradient, deformation_gradient_p)?;
Ok((deformation_gradient_e.transpose()
* cauchy_stress
* deformation_gradient_e.inverse_transpose())
* jacobian)
}
fn second_piola_kirchhoff_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
Ok(deformation_gradient.inverse()
* self.first_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)?)
}
fn second_piola_kirchhoff_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_p: &DeformationGradientPlastic,
) -> Result<SecondPiolaKirchhoffTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
let deformation_gradient_inverse = deformation_gradient_inverse_transpose.transpose();
let second_piola_kirchhoff_stress =
self.second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)?;
Ok(self
.cauchy_tangent_stiffness(deformation_gradient, deformation_gradient_p)?
.contract_first_second_with_second(
&deformation_gradient_inverse,
&deformation_gradient_inverse,
)
* deformation_gradient.determinant()
+ SecondPiolaKirchhoffTangentStiffness::dyad_ij_kl(
&second_piola_kirchhoff_stress,
&deformation_gradient_inverse_transpose,
)
- SecondPiolaKirchhoffTangentStiffness::dyad_il_kj(
&second_piola_kirchhoff_stress,
&deformation_gradient_inverse_transpose,
)
- SecondPiolaKirchhoffTangentStiffness::dyad_ik_jl(
&deformation_gradient_inverse,
&second_piola_kirchhoff_stress,
))
}
}
pub trait ElasticPlastic
where
Self: ElasticPlasticOrViscoplastic,
{
}