conspire 0.6.0

The Rust interface to conspire.
Documentation
pub mod elastic;
pub mod linear;

use crate::{
    fem::block::element::{
        ElementNodalCoordinates, ElementNodalEitherCoordinates, FiniteElement,
        ShapeFunctionsAtIntegrationPoints, surface::SurfaceFiniteElement,
    },
    math::{ScalarList, Tensor},
    mechanics::{CurrentCoordinate, NormalGradients},
};
use std::fmt::{self, Debug, Formatter};

pub type Separation = CurrentCoordinate;
pub type Separations<const P: usize> = ElementNodalCoordinates<P>;

const M: usize = 2;

#[derive(Clone)]
pub struct CohesiveElement<const G: usize, const N: usize, const O: usize> {
    integration_weights: ScalarList<G>,
}

impl<const G: usize, const N: usize, const O: usize> Debug for CohesiveElement<G, N, O> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let element = match (G, N, O) {
            (3, 6, 1) => "LinearCohesiveWedge",
            (4, 8, 1) => "LinearCohesiveHexahedron",
            _ => panic!(),
        };
        write!(f, "{element} {{ G: {G}, N: {N} }}",)
    }
}

impl<const G: usize, const N: usize, const O: usize, const P: usize> SurfaceFiniteElement<G, N, P>
    for CohesiveElement<G, N, O>
where
    Self: FiniteElement<G, M, N, P>,
{
}

pub trait CohesiveFiniteElement<const G: usize, const N: usize, const P: usize>
where
    Self: SurfaceFiniteElement<G, N, P>,
{
    fn nodal_mid_surface<const I: usize>(
        nodal_coordinates: &ElementNodalEitherCoordinates<I, N>,
    ) -> ElementNodalEitherCoordinates<I, P>;
    fn nodal_separations(nodal_coordinates: &ElementNodalCoordinates<N>) -> Separations<P>;
    fn normal_gradients_full(
        nodal_mid_surface: &ElementNodalCoordinates<P>,
    ) -> NormalGradients<N, G>;
    fn separations(nodal_coordinates: &ElementNodalCoordinates<N>) -> Separations<G> {
        Self::shape_functions_at_integration_points()
            .into_iter()
            .map(|shape_functions| {
                Self::nodal_separations(nodal_coordinates)
                    .into_iter()
                    .zip(shape_functions.iter())
                    .map(|(nodal_separation, shape_function)| nodal_separation * shape_function)
                    .sum()
            })
            .collect()
    }
    fn signed_shape_functions() -> ShapeFunctionsAtIntegrationPoints<G, N> {
        Self::shape_functions_at_integration_points()
            .into_iter()
            .map(|shape_functions| {
                shape_functions
                    .iter()
                    .chain(shape_functions.iter())
                    .zip(Self::signs())
                    .map(|(shape_function, sign)| shape_function * sign)
                    .collect()
            })
            .collect()
    }
    fn signs() -> ScalarList<N>;
}