conspire 0.7.7

The Rust interface to conspire.
Documentation
use crate::{
    constitutive::solid::elastic_viscoplastic::ElasticViscoplastic,
    fem::block::element::{
        Element, ElementNodalCoordinates, FiniteElement, FiniteElementError,
        solid::{
            ElementNodalForcesSolid, ElementNodalStiffnessesSolid, SolidFiniteElement,
            viscoplastic::{ViscoplasticEvolution, ViscoplasticStateVariables},
        },
    },
    math::{ContractSecondFourthWithFirst, Differentiate, Tensor},
    mechanics::{FirstPiolaKirchhoffStressList, FirstPiolaKirchhoffTangentStiffnessList},
};

pub trait ElasticViscoplasticFiniteElement<
    C,
    const G: usize,
    const M: usize,
    const N: usize,
    const P: usize,
    Y,
> where
    C: ElasticViscoplastic<Y>,
    Self: SolidFiniteElement<G, M, N, P>,
    Y: Differentiate + Tensor,
{
    fn nodal_forces(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError>;
    fn nodal_stiffnesses(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError>;
    fn state_variables_evolution(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ViscoplasticEvolution<G, Y>, FiniteElementError>;
}

impl<C, const G: usize, const N: usize, const O: usize, const P: usize, Y>
    ElasticViscoplasticFiniteElement<C, G, 3, N, P, Y> for Element<3, G, N, O>
where
    C: ElasticViscoplastic<Y>,
    Self: SolidFiniteElement<G, 3, N, P>,
    Y: Differentiate + Tensor,
{
    fn nodal_forces(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError> {
        let first_piola_kirchhoff_stresses = self
            .deformation_gradients(nodal_coordinates)
            .iter()
            .zip(state_variables)
            .map(|(deformation_gradient, state_variable)| {
                let (deformation_gradient_p, _) = state_variable.into();
                constitutive_model
                    .first_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)
            })
            .collect::<Result<FirstPiolaKirchhoffStressList<G>, _>>()
            .map_err(|error| FiniteElementError::upstream(error, self))?;
        Ok(first_piola_kirchhoff_stresses
            .iter()
            .zip(
                self.gradient_vectors()
                    .iter()
                    .zip(self.integration_weights()),
            )
            .map(
                |(first_piola_kirchhoff_stress, (gradient_vectors, integration_weight))| {
                    gradient_vectors
                        .iter()
                        .map(|gradient_vector| {
                            (first_piola_kirchhoff_stress * gradient_vector) * integration_weight
                        })
                        .collect()
                },
            )
            .sum())
    }
    fn nodal_stiffnesses(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
        let first_piola_kirchhoff_tangent_stiffnesses = self
            .deformation_gradients(nodal_coordinates)
            .iter()
            .zip(state_variables)
            .map(|(deformation_gradient, state_variable)| {
                let (deformation_gradient_p, _) = state_variable.into();
                constitutive_model.first_piola_kirchhoff_tangent_stiffness(
                    deformation_gradient,
                    deformation_gradient_p,
                )
            })
            .collect::<Result<FirstPiolaKirchhoffTangentStiffnessList<G>, _>>()
            .map_err(|error| FiniteElementError::upstream(error, self))?;
        Ok(first_piola_kirchhoff_tangent_stiffnesses
            .iter()
            .zip(
                self.gradient_vectors()
                    .iter()
                    .zip(self.integration_weights()),
            )
            .map(
                |(
                    first_piola_kirchhoff_tangent_stiffness,
                    (gradient_vectors, integration_weight),
                )| {
                    gradient_vectors
                        .iter()
                        .map(|gradient_vector_a| {
                            gradient_vectors
                                .iter()
                                .map(|gradient_vector_b| {
                                    first_piola_kirchhoff_tangent_stiffness
                                        .contract_second_fourth_with_first(
                                            gradient_vector_a,
                                            gradient_vector_b,
                                        )
                                        * integration_weight
                                })
                                .collect()
                        })
                        .collect()
                },
            )
            .sum())
    }
    fn state_variables_evolution(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
        state_variables: &ViscoplasticStateVariables<G, Y>,
    ) -> Result<ViscoplasticEvolution<G, Y>, FiniteElementError> {
        self.deformation_gradients(nodal_coordinates)
            .iter()
            .zip(state_variables)
            .map(|(deformation_gradient, state_variable)| {
                constitutive_model.state_variables_evolution(deformation_gradient, state_variable)
            })
            .collect::<Result<ViscoplasticEvolution<G, Y>, _>>()
            .map_err(|error| FiniteElementError::upstream(error, self))
    }
}