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

1use crate::{
2    constitutive::cohesive::elastic::Elastic,
3    fem::block::element::{
4        ElementNodalCoordinates, FiniteElement, FiniteElementError,
5        cohesive::{CohesiveElement, CohesiveFiniteElement},
6        solid::{ElementNodalForcesSolid, ElementNodalStiffnessesSolid},
7        surface::SurfaceFiniteElement,
8    },
9    math::{Rank2, Tensor, TensorRank2List2D},
10    mechanics::TractionList,
11};
12
13pub type StiffnessCohesiveList<const N: usize> = TensorRank2List2D<3, 1, 1, 2, N>;
14
15pub trait ElasticCohesiveElement<C, const G: usize, const N: usize, const P: usize>
16where
17    C: Elastic,
18    Self: CohesiveFiniteElement<G, N, P>,
19{
20    fn nodal_forces(
21        &self,
22        constitutive_model: &C,
23        nodal_coordinates: &ElementNodalCoordinates<N>,
24    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError>;
25    fn nodal_stiffnesses(
26        &self,
27        constitutive_model: &C,
28        nodal_coordinates: &ElementNodalCoordinates<N>,
29    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError>;
30}
31
32impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
33    ElasticCohesiveElement<C, G, N, P> for CohesiveElement<G, N, O>
34where
35    C: Elastic,
36    Self: CohesiveFiniteElement<G, N, P>,
37{
38    fn nodal_forces(
39        &self,
40        constitutive_model: &C,
41        nodal_coordinates: &ElementNodalCoordinates<N>,
42    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError> {
43        let normals = Self::normals(&Self::nodal_mid_surface(nodal_coordinates));
44        match Self::separations(nodal_coordinates)
45            .into_iter()
46            .zip(normals)
47            .map(|(separation, normal)| constitutive_model.traction(separation, normal))
48            .collect::<Result<TractionList<G>, _>>()
49        {
50            Ok(tractions) => Ok(tractions
51                .into_iter()
52                .zip(
53                    Self::signed_shape_functions()
54                        .into_iter()
55                        .zip(self.integration_weights()),
56                )
57                .map(|(traction, (signed_shape_functions, integration_weight))| {
58                    signed_shape_functions
59                        .iter()
60                        .map(|signed_shape_function| {
61                            &traction * (signed_shape_function * integration_weight)
62                        })
63                        .collect()
64                })
65                .sum()),
66            Err(error) => Err(FiniteElementError::Upstream(
67                format!("{error}"),
68                format!("{self:?}"),
69            )),
70        }
71    }
72    fn nodal_stiffnesses(
73        &self,
74        constitutive_model: &C,
75        nodal_coordinates: &ElementNodalCoordinates<N>,
76    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
77        let nodal_mid_surface = Self::nodal_mid_surface(nodal_coordinates);
78        let normals = Self::normals(&nodal_mid_surface);
79        let normal_gradients = Self::normal_gradients_full(&nodal_mid_surface);
80        match Self::separations(nodal_coordinates)
81            .into_iter()
82            .zip(normals)
83            .map(|(separation, normal)| constitutive_model.stiffness(separation, normal))
84            .collect::<Result<StiffnessCohesiveList<G>, _>>()
85        {
86            Ok(stiffnesses) => Ok(stiffnesses
87                .into_iter()
88                .zip(
89                    Self::signed_shape_functions()
90                        .into_iter()
91                        .zip(normal_gradients.into_iter().zip(self.integration_weights())),
92                )
93                .map(
94                    |(
95                        stiffness,
96                        (signed_shape_functions, (normal_gradient, integration_weight)),
97                    )| {
98                        let [stiffness_u, stiffness_n] = stiffness.into();
99                        signed_shape_functions
100                            .iter()
101                            .map(|signed_shape_function_a| {
102                                signed_shape_functions
103                                    .iter()
104                                    .zip(normal_gradient.iter())
105                                    .map(|(signed_shape_function_b, normal_gradient_b)| {
106                                        (&stiffness_u * signed_shape_function_b
107                                            + (&stiffness_n * normal_gradient_b.transpose()) * 0.5)
108                                            * (signed_shape_function_a * integration_weight)
109                                    })
110                                    .collect()
111                            })
112                            .collect()
113                    },
114                )
115                .sum()),
116            Err(error) => Err(FiniteElementError::Upstream(
117                format!("{error}"),
118                format!("{self:?}"),
119            )),
120        }
121    }
122}