#[cfg(test)]
pub mod test;
use super::{super::fluid::viscous::Viscous, *};
use crate::math::{
Matrix, Vector,
integrate::{ImplicitDaeFirstOrderRoot, ImplicitDaeZerothOrderRoot},
optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
};
pub enum AppliedLoad<'a> {
UniaxialStress(fn(Scalar) -> Scalar, &'a [Scalar]),
BiaxialStress(fn(Scalar) -> Scalar, fn(Scalar) -> Scalar, &'a [Scalar]),
}
pub trait Viscoelastic
where
Self: Solid + Viscous,
{
fn cauchy_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<CauchyStress, ConstitutiveError> {
Ok(deformation_gradient
* self
.second_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_rate)?
* deformation_gradient.transpose()
/ deformation_gradient.determinant())
}
fn cauchy_rate_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<CauchyRateTangentStiffness, ConstitutiveError> {
Ok(self
.second_piola_kirchhoff_rate_tangent_stiffness(
deformation_gradient,
deformation_gradient_rate,
)?
.contract_first_second_indices_with_second_indices_of(
deformation_gradient,
deformation_gradient,
)
/ deformation_gradient.determinant())
}
fn first_piola_kirchhoff_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
Ok(
self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
* deformation_gradient.inverse_transpose()
* deformation_gradient.determinant(),
)
}
fn first_piola_kirchhoff_rate_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<FirstPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
Ok(self
.cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
.contract_second_index_with_first_index_of(&deformation_gradient.inverse_transpose())
* deformation_gradient.determinant())
}
fn second_piola_kirchhoff_stress(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
Ok(deformation_gradient.inverse()
* self.cauchy_stress(deformation_gradient, deformation_gradient_rate)?
* deformation_gradient.inverse_transpose()
* deformation_gradient.determinant())
}
fn second_piola_kirchhoff_rate_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate,
) -> Result<SecondPiolaKirchhoffRateTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse = deformation_gradient.inverse();
Ok(self
.cauchy_rate_tangent_stiffness(deformation_gradient, deformation_gradient_rate)?
.contract_first_second_indices_with_second_indices_of(
&deformation_gradient_inverse,
&deformation_gradient_inverse,
)
* deformation_gradient.determinant())
}
}
pub trait ZerothOrderRoot {
fn root(
&self,
applied_load: AppliedLoad,
integrator: impl ImplicitDaeZerothOrderRoot<DeformationGradient, DeformationGradients>,
solver: impl ZerothOrderRootFinding<DeformationGradient>,
) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
}
pub trait FirstOrderRoot {
fn root(
&self,
applied_load: AppliedLoad,
integrator: impl ImplicitDaeFirstOrderRoot<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffRateTangentStiffness,
DeformationGradientRate,
DeformationGradientRates,
>,
solver: impl FirstOrderRootFinding<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffRateTangentStiffness,
DeformationGradientRate,
>,
) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError>;
}
impl<T> ZerothOrderRoot for T
where
T: Viscoelastic,
{
fn root(
&self,
applied_load: AppliedLoad,
integrator: impl ImplicitDaeZerothOrderRoot<DeformationGradient, DeformationGradients>,
solver: impl ZerothOrderRootFinding<DeformationGradientRate>,
) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
match match applied_load {
AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
let mut matrix = Matrix::zero(4, 9);
let mut vector = Vector::zero(4);
matrix[0][0] = 1.0;
matrix[1][1] = 1.0;
matrix[2][2] = 1.0;
matrix[3][5] = 1.0;
integrator.integrate(
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_stress(
deformation_gradient,
deformation_gradient_rate,
)?)
},
solver,
time,
DeformationGradient::identity(),
|t: Scalar| {
vector[0] = deformation_gradient_rate_11(t);
EqualityConstraint::Linear(matrix.clone(), vector.clone())
},
)
}
AppliedLoad::BiaxialStress(
deformation_gradient_rate_11,
deformation_gradient_rate_22,
time,
) => {
let mut matrix = Matrix::zero(5, 9);
let mut vector = Vector::zero(5);
matrix[0][0] = 1.0;
matrix[1][1] = 1.0;
matrix[2][2] = 1.0;
matrix[3][5] = 1.0;
matrix[4][4] = 1.0;
integrator.integrate(
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_stress(
deformation_gradient,
deformation_gradient_rate,
)?)
},
solver,
time,
DeformationGradient::identity(),
|t: Scalar| {
vector[0] = deformation_gradient_rate_11(t);
vector[4] = deformation_gradient_rate_22(t);
EqualityConstraint::Linear(matrix.clone(), vector.clone())
},
)
}
} {
Ok(results) => Ok(results),
Err(error) => Err(ConstitutiveError::Upstream(
format!("{error}"),
format!("{self:?}"),
)),
}
}
}
impl<T> FirstOrderRoot for T
where
T: Viscoelastic,
{
fn root(
&self,
applied_load: AppliedLoad,
integrator: impl ImplicitDaeFirstOrderRoot<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffRateTangentStiffness,
DeformationGradientRate,
DeformationGradientRates,
>,
solver: impl FirstOrderRootFinding<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffRateTangentStiffness,
DeformationGradientRate,
>,
) -> Result<(Times, DeformationGradients, DeformationGradientRates), ConstitutiveError> {
match match applied_load {
AppliedLoad::UniaxialStress(deformation_gradient_rate_11, time) => {
let mut matrix = Matrix::zero(4, 9);
let mut vector = Vector::zero(4);
matrix[0][0] = 1.0;
matrix[1][1] = 1.0;
matrix[2][2] = 1.0;
matrix[3][5] = 1.0;
integrator.integrate(
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_stress(
deformation_gradient,
deformation_gradient_rate,
)?)
},
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
deformation_gradient,
deformation_gradient_rate,
)?)
},
solver,
time,
DeformationGradient::identity(),
|t: Scalar| {
vector[0] = deformation_gradient_rate_11(t);
EqualityConstraint::Linear(matrix.clone(), vector.clone())
},
)
}
AppliedLoad::BiaxialStress(
deformation_gradient_rate_11,
deformation_gradient_rate_22,
time,
) => {
let mut matrix = Matrix::zero(5, 9);
let mut vector = Vector::zero(5);
matrix[0][0] = 1.0;
matrix[1][1] = 1.0;
matrix[2][2] = 1.0;
matrix[3][5] = 1.0;
matrix[4][4] = 1.0;
integrator.integrate(
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_stress(
deformation_gradient,
deformation_gradient_rate,
)?)
},
|_: Scalar,
deformation_gradient: &DeformationGradient,
deformation_gradient_rate: &DeformationGradientRate| {
Ok(self.first_piola_kirchhoff_rate_tangent_stiffness(
deformation_gradient,
deformation_gradient_rate,
)?)
},
solver,
time,
DeformationGradient::identity(),
|t: Scalar| {
vector[0] = deformation_gradient_rate_11(t);
vector[4] = deformation_gradient_rate_22(t);
EqualityConstraint::Linear(matrix.clone(), vector.clone())
},
)
}
} {
Ok(results) => Ok(results),
Err(error) => Err(ConstitutiveError::Upstream(
format!("{error}"),
format!("{self:?}"),
)),
}
}
}