conspire 0.6.0

The Rust interface to conspire.
Documentation
//! Hyperelastic solid constitutive models.
//!
//! ---
//!
#![doc = include_str!("doc.md")]

#[cfg(feature = "doc")]
pub mod doc;

#[cfg(test)]
pub mod test;

pub mod internal_variables;

mod arruda_boyce;
mod eight_chain;
mod fung;
mod gent;
mod hencky;
mod mooney_rivlin;
mod neo_hookean;
mod saint_venant_kirchhoff;
mod yeoh;

pub use self::{
    arruda_boyce::ArrudaBoyce, eight_chain::EightChain, fung::Fung, gent::Gent, hencky::Hencky,
    mooney_rivlin::MooneyRivlin, neo_hookean::NeoHookean,
    saint_venant_kirchhoff::SaintVenantKirchhoff, yeoh::Yeoh,
};
use super::{
    elastic::{AppliedLoad, Elastic, bcs},
    *,
};
use crate::math::optimize::{EqualityConstraint, FirstOrderOptimization, SecondOrderOptimization};

/// Required methods for hyperelastic solid constitutive models.
pub trait Hyperelastic
where
    Self: Elastic,
{
    /// Calculates and returns the Helmholtz free energy density.
    ///
    /// ```math
    /// a = a(\mathbf{F})
    /// ```
    fn helmholtz_free_energy_density(
        &self,
        deformation_gradient: &DeformationGradient,
    ) -> Result<Scalar, ConstitutiveError>;
}

/// First-order minimization methods for elastic solid constitutive models.
pub trait FirstOrderMinimize {
    /// Solve for the unknown components of the deformation gradient under an applied load.
    ///
    /// ```math
    /// \Pi(\mathbf{F},\boldsymbol{\lambda}) = a(\mathbf{F}) - \boldsymbol{\lambda}:(\mathbf{F} - \mathbf{F}_0) - \mathbf{P}_0:\mathbf{F}
    /// ```
    fn minimize(
        &self,
        applied_load: AppliedLoad,
        solver: impl FirstOrderOptimization<Scalar, DeformationGradient>,
    ) -> Result<DeformationGradient, ConstitutiveError>;
}

/// Second-order minimization methods for elastic solid constitutive models.
pub trait SecondOrderMinimize {
    /// Solve for the unknown components of the deformation gradient under an applied load.
    ///
    /// ```math
    /// \Pi(\mathbf{F},\boldsymbol{\lambda}) = a(\mathbf{F}) - \boldsymbol{\lambda}:(\mathbf{F} - \mathbf{F}_0) - \mathbf{P}_0:\mathbf{F}
    /// ```
    fn minimize(
        &self,
        applied_load: AppliedLoad,
        solver: impl SecondOrderOptimization<
            Scalar,
            FirstPiolaKirchhoffStress,
            FirstPiolaKirchhoffTangentStiffness,
            DeformationGradient,
        >,
    ) -> Result<DeformationGradient, ConstitutiveError>;
}

impl<T> FirstOrderMinimize for T
where
    T: Hyperelastic,
{
    fn minimize(
        &self,
        applied_load: AppliedLoad,
        solver: impl FirstOrderOptimization<Scalar, DeformationGradient>,
    ) -> Result<DeformationGradient, ConstitutiveError> {
        let (matrix, vector) = bcs(applied_load);
        match solver.minimize(
            |deformation_gradient: &DeformationGradient| {
                Ok(self.helmholtz_free_energy_density(deformation_gradient)?)
            },
            |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> SecondOrderMinimize for T
where
    T: Hyperelastic,
{
    fn minimize(
        &self,
        applied_load: AppliedLoad,
        solver: impl SecondOrderOptimization<
            Scalar,
            FirstPiolaKirchhoffStress,
            FirstPiolaKirchhoffTangentStiffness,
            DeformationGradient,
        >,
    ) -> Result<DeformationGradient, ConstitutiveError> {
        let (matrix, vector) = bcs(applied_load);
        match solver.minimize(
            |deformation_gradient: &DeformationGradient| {
                Ok(self.helmholtz_free_energy_density(deformation_gradient)?)
            },
            |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),
            None,
        ) {
            Ok(deformation_gradient) => Ok(deformation_gradient),
            Err(error) => Err(ConstitutiveError::Upstream(
                format!("{error}"),
                format!("{self:?}"),
            )),
        }
    }
}