Skip to main content

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

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