#![doc = include_str!("doc.md")]
#[cfg(feature = "doc")]
pub mod doc;
#[cfg(test)]
pub mod test;
pub mod internal_variables;
mod almansi_hamel;
mod hencky;
mod saint_venant_kirchhoff;
pub use self::{
almansi_hamel::AlmansiHamel, hencky::Hencky, saint_venant_kirchhoff::SaintVenantKirchhoff,
};
use super::*;
use crate::math::{
Matrix, Vector,
optimize::{EqualityConstraint, FirstOrderRootFinding, ZerothOrderRootFinding},
};
pub enum AppliedLoad {
UniaxialStress(Scalar),
BiaxialStress(Scalar, Scalar),
}
pub trait Elastic
where
Self: Solid,
{
fn cauchy_stress(
&self,
deformation_gradient: &DeformationGradient,
) -> Result<CauchyStress, ConstitutiveError> {
Ok(deformation_gradient
* self.second_piola_kirchhoff_stress(deformation_gradient)?
* deformation_gradient.transpose()
/ deformation_gradient.determinant())
}
fn cauchy_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
) -> Result<CauchyTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
let cauchy_stress = self.cauchy_stress(deformation_gradient)?;
let some_stress = &cauchy_stress * &deformation_gradient_inverse_transpose;
Ok(self
.second_piola_kirchhoff_tangent_stiffness(deformation_gradient)?
.contract_first_second_indices_with_second_indices_of(
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,
) -> Result<FirstPiolaKirchhoffStress, ConstitutiveError> {
Ok(self.cauchy_stress(deformation_gradient)?
* deformation_gradient.inverse_transpose()
* deformation_gradient.determinant())
}
fn first_piola_kirchhoff_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
) -> Result<FirstPiolaKirchhoffTangentStiffness, ConstitutiveError> {
let deformation_gradient_inverse_transpose = deformation_gradient.inverse_transpose();
let first_piola_kirchhoff_stress =
self.first_piola_kirchhoff_stress(deformation_gradient)?;
Ok(self
.cauchy_tangent_stiffness(deformation_gradient)?
.contract_second_index_with_first_index_of(&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 second_piola_kirchhoff_stress(
&self,
deformation_gradient: &DeformationGradient,
) -> Result<SecondPiolaKirchhoffStress, ConstitutiveError> {
Ok(deformation_gradient.inverse()
* self.first_piola_kirchhoff_stress(deformation_gradient)?)
}
fn second_piola_kirchhoff_tangent_stiffness(
&self,
deformation_gradient: &DeformationGradient,
) -> 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)?;
Ok(self
.cauchy_tangent_stiffness(deformation_gradient)?
.contract_first_second_indices_with_second_indices_of(
&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 ZerothOrderRoot {
fn root(
&self,
applied_load: AppliedLoad,
solver: impl ZerothOrderRootFinding<DeformationGradient>,
) -> Result<DeformationGradient, ConstitutiveError>;
}
pub trait FirstOrderRoot {
fn root(
&self,
applied_load: AppliedLoad,
solver: impl FirstOrderRootFinding<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffTangentStiffness,
DeformationGradient,
>,
) -> Result<DeformationGradient, ConstitutiveError>;
}
impl<T> ZerothOrderRoot for T
where
T: Elastic,
{
fn root(
&self,
applied_load: AppliedLoad,
solver: impl ZerothOrderRootFinding<DeformationGradient>,
) -> Result<DeformationGradient, ConstitutiveError> {
let (matrix, vector) = bcs(applied_load);
match solver.root(
|deformation_gradient: &DeformationGradient| {
Ok(self.first_piola_kirchhoff_stress(deformation_gradient)?)
},
DeformationGradient::identity(),
EqualityConstraint::Linear(matrix, vector),
) {
Ok(deformation_gradient) => Ok(deformation_gradient),
Err(error) => Err(ConstitutiveError::Upstream(
format!("{error}"),
format!("{self:?}"),
)),
}
}
}
impl<T> FirstOrderRoot for T
where
T: Elastic,
{
fn root(
&self,
applied_load: AppliedLoad,
solver: impl FirstOrderRootFinding<
FirstPiolaKirchhoffStress,
FirstPiolaKirchhoffTangentStiffness,
DeformationGradient,
>,
) -> Result<DeformationGradient, ConstitutiveError> {
let (matrix, vector) = bcs(applied_load);
match solver.root(
|deformation_gradient: &DeformationGradient| {
Ok(self.first_piola_kirchhoff_stress(deformation_gradient)?)
},
|deformation_gradient: &DeformationGradient| {
Ok(self.first_piola_kirchhoff_tangent_stiffness(deformation_gradient)?)
},
DeformationGradient::identity(),
EqualityConstraint::Linear(matrix, vector),
) {
Ok(deformation_gradient) => Ok(deformation_gradient),
Err(error) => Err(ConstitutiveError::Upstream(
format!("{error}"),
format!("{self:?}"),
)),
}
}
}
#[doc(hidden)]
pub fn bcs(applied_load: AppliedLoad) -> (Matrix, Vector) {
match applied_load {
AppliedLoad::UniaxialStress(deformation_gradient_11) => {
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;
vector[0] = deformation_gradient_11;
(matrix, vector)
}
AppliedLoad::BiaxialStress(deformation_gradient_11, deformation_gradient_22) => {
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;
vector[0] = deformation_gradient_11;
vector[4] = deformation_gradient_22;
(matrix, vector)
}
}
}