conspire/domain/fem/block/element/cohesive/linear/
mod.rs

1mod hexahedron;
2mod wedge;
3
4pub use hexahedron::Hexahedron;
5pub use wedge::Wedge;
6
7use crate::{
8    fem::block::element::{
9        ElementNodalCoordinates, ElementNodalEitherCoordinates, ElementNodalReferenceCoordinates,
10        FiniteElement,
11        cohesive::{CohesiveElement, Separations},
12        surface::SurfaceFiniteElement,
13    },
14    math::{ScalarList, Tensor},
15    mechanics::NormalGradients,
16};
17use std::iter::repeat_n;
18
19pub type LinearCohesiveElement<const G: usize, const N: usize> = CohesiveElement<G, N, 1>;
20
21pub trait LinearCohesiveFiniteElement<const G: usize, const N: usize, const P: usize>
22where
23    Self: FiniteElement<G, 2, N, P> + SurfaceFiniteElement<G, N, P>,
24{
25    fn from_linear(
26        reference_nodal_coordinates: ElementNodalReferenceCoordinates<N>,
27    ) -> LinearCohesiveElement<G, N> {
28        let integration_weights = Self::bases(&Self::nodal_mid_surface_linear(
29            &reference_nodal_coordinates,
30        ))
31        .into_iter()
32        .zip(Self::parametric_weights())
33        .map(|(reference_basis, parametric_weight)| {
34            reference_basis[0].cross(&reference_basis[1]).norm() * parametric_weight
35        })
36        .collect();
37        LinearCohesiveElement {
38            integration_weights,
39        }
40    }
41    fn nodal_mid_surface_linear<const I: usize>(
42        nodal_coordinates: &ElementNodalEitherCoordinates<I, N>,
43    ) -> ElementNodalEitherCoordinates<I, P> {
44        nodal_coordinates
45            .iter()
46            .take(P)
47            .zip(nodal_coordinates.iter().skip(P))
48            .map(|(coordinates_bottom, coordinates_top)| {
49                (coordinates_top + coordinates_bottom) * 0.5
50            })
51            .collect()
52    }
53    fn nodal_separations_linear(nodal_coordinates: &ElementNodalCoordinates<N>) -> Separations<P> {
54        nodal_coordinates
55            .iter()
56            .take(P)
57            .zip(nodal_coordinates.iter().skip(P))
58            .map(|(coordinates_bottom, coordinates_top)| coordinates_top - coordinates_bottom)
59            .collect()
60    }
61    fn normal_gradients_full_linear(
62        nodal_mid_surface: &ElementNodalCoordinates<P>,
63    ) -> NormalGradients<N, G> {
64        Self::normal_gradients(nodal_mid_surface)
65            .into_iter()
66            .map(|normal_gradient| {
67                normal_gradient
68                    .iter()
69                    .chain(normal_gradient.iter())
70                    .cloned()
71                    .collect()
72            })
73            .collect()
74    }
75    fn signs_linear() -> ScalarList<N> {
76        repeat_n(-1.0, P).chain(repeat_n(1.0, P)).collect()
77    }
78}