conspire/domain/fem/block/element/cohesive/elastic/
mod.rs1use 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}