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