conspire 0.7.7

The Rust interface to conspire.
Documentation
use crate::constitutive::cohesive::elastic::StiffnessCohesive;
use crate::{
    constitutive::cohesive::elastic::Elastic,
    fem::block::element::{
        ElementNodalCoordinates, FiniteElement, FiniteElementError,
        cohesive::{CohesiveElement, CohesiveFiniteElement},
        solid::{ElementNodalForcesSolid, ElementNodalStiffnessesSolid},
        surface::SurfaceFiniteElement,
    },
    math::{Rank2, Tensor, TensorList, TensorTuple},
    mechanics::TractionList,
};

pub type StiffnessCohesiveList<const N: usize> = TensorList<StiffnessCohesive, N>;

pub trait ElasticCohesiveElement<C, const G: usize, const N: usize, const P: usize>
where
    C: Elastic,
    Self: CohesiveFiniteElement<G, N, P>,
{
    fn nodal_forces(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError>;
    fn nodal_stiffnesses(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError>;
}

impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
    ElasticCohesiveElement<C, G, N, P> for CohesiveElement<G, N, O>
where
    C: Elastic,
    Self: CohesiveFiniteElement<G, N, P>,
{
    fn nodal_forces(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError> {
        let normals = Self::normals(&Self::nodal_mid_surface(nodal_coordinates));
        let tractions = Self::separations(nodal_coordinates)
            .into_iter()
            .zip(normals)
            .map(|(separation, normal)| constitutive_model.traction(separation, normal))
            .collect::<Result<TractionList<G>, _>>()
            .map_err(|error| FiniteElementError::upstream(error, self))?;
        Ok(tractions
            .into_iter()
            .zip(
                Self::signed_shape_functions()
                    .into_iter()
                    .zip(self.integration_weights()),
            )
            .map(|(traction, (signed_shape_functions, integration_weight))| {
                signed_shape_functions
                    .iter()
                    .map(|signed_shape_function| {
                        &traction * (signed_shape_function * integration_weight)
                    })
                    .collect()
            })
            .sum())
    }
    fn nodal_stiffnesses(
        &self,
        constitutive_model: &C,
        nodal_coordinates: &ElementNodalCoordinates<N>,
    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
        let nodal_mid_surface = Self::nodal_mid_surface(nodal_coordinates);
        let normals = Self::normals(&nodal_mid_surface);
        let normal_gradients = Self::normal_gradients_full(&nodal_mid_surface);
        let stiffnesses = Self::separations(nodal_coordinates)
            .into_iter()
            .zip(normals)
            .map(|(separation, normal)| constitutive_model.stiffness(separation, normal))
            .collect::<Result<StiffnessCohesiveList<G>, _>>()
            .map_err(|error| FiniteElementError::upstream(error, self))?;
        Ok(stiffnesses
            .into_iter()
            .zip(
                Self::signed_shape_functions()
                    .into_iter()
                    .zip(normal_gradients.into_iter().zip(self.integration_weights())),
            )
            .map(
                |(stiffness, (signed_shape_functions, (normal_gradient, integration_weight)))| {
                    let TensorTuple(stiffness_u, stiffness_n) = stiffness;
                    signed_shape_functions
                        .iter()
                        .map(|signed_shape_function_a| {
                            signed_shape_functions
                                .iter()
                                .zip(normal_gradient.iter())
                                .map(|(signed_shape_function_b, normal_gradient_b)| {
                                    (&stiffness_u * signed_shape_function_b
                                        + (&stiffness_n * normal_gradient_b.transpose()) * 0.5)
                                        * (signed_shape_function_a * integration_weight)
                                })
                                .collect()
                        })
                        .collect()
                },
            )
            .sum())
    }
}