Skip to main content

conspire/domain/fem/block/element/solid/elastic_viscoplastic/
mod.rs

1use crate::{
2    constitutive::solid::elastic_viscoplastic::ElasticViscoplastic,
3    fem::block::element::{
4        Element, ElementNodalCoordinates, FiniteElement, FiniteElementError,
5        solid::{
6            ElementNodalForcesSolid, ElementNodalStiffnessesSolid, SolidFiniteElement,
7            viscoplastic::{ViscoplasticEvolution, ViscoplasticStateVariables},
8        },
9    },
10    math::{ContractSecondFourthWithFirst, Differentiate, Tensor},
11    mechanics::{FirstPiolaKirchhoffStressList, FirstPiolaKirchhoffTangentStiffnessList},
12};
13
14pub trait ElasticViscoplasticFiniteElement<
15    C,
16    const G: usize,
17    const M: usize,
18    const N: usize,
19    const P: usize,
20    Y,
21> where
22    C: ElasticViscoplastic<Y>,
23    Self: SolidFiniteElement<G, M, N, P>,
24    Y: Differentiate + Tensor,
25{
26    fn nodal_forces(
27        &self,
28        constitutive_model: &C,
29        nodal_coordinates: &ElementNodalCoordinates<N>,
30        state_variables: &ViscoplasticStateVariables<G, Y>,
31    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError>;
32    fn nodal_stiffnesses(
33        &self,
34        constitutive_model: &C,
35        nodal_coordinates: &ElementNodalCoordinates<N>,
36        state_variables: &ViscoplasticStateVariables<G, Y>,
37    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError>;
38    fn state_variables_evolution(
39        &self,
40        constitutive_model: &C,
41        nodal_coordinates: &ElementNodalCoordinates<N>,
42        state_variables: &ViscoplasticStateVariables<G, Y>,
43    ) -> Result<ViscoplasticEvolution<G, Y>, FiniteElementError>;
44}
45
46impl<C, const G: usize, const N: usize, const O: usize, const P: usize, Y>
47    ElasticViscoplasticFiniteElement<C, G, 3, N, P, Y> for Element<3, G, N, O>
48where
49    C: ElasticViscoplastic<Y>,
50    Self: SolidFiniteElement<G, 3, N, P>,
51    Y: Differentiate + Tensor,
52{
53    fn nodal_forces(
54        &self,
55        constitutive_model: &C,
56        nodal_coordinates: &ElementNodalCoordinates<N>,
57        state_variables: &ViscoplasticStateVariables<G, Y>,
58    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError> {
59        let first_piola_kirchhoff_stresses = self
60            .deformation_gradients(nodal_coordinates)
61            .iter()
62            .zip(state_variables)
63            .map(|(deformation_gradient, state_variable)| {
64                let (deformation_gradient_p, _) = state_variable.into();
65                constitutive_model
66                    .first_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)
67            })
68            .collect::<Result<FirstPiolaKirchhoffStressList<G>, _>>()
69            .map_err(|error| FiniteElementError::upstream(error, self))?;
70        Ok(first_piola_kirchhoff_stresses
71            .iter()
72            .zip(
73                self.gradient_vectors()
74                    .iter()
75                    .zip(self.integration_weights()),
76            )
77            .map(
78                |(first_piola_kirchhoff_stress, (gradient_vectors, integration_weight))| {
79                    gradient_vectors
80                        .iter()
81                        .map(|gradient_vector| {
82                            (first_piola_kirchhoff_stress * gradient_vector) * integration_weight
83                        })
84                        .collect()
85                },
86            )
87            .sum())
88    }
89    fn nodal_stiffnesses(
90        &self,
91        constitutive_model: &C,
92        nodal_coordinates: &ElementNodalCoordinates<N>,
93        state_variables: &ViscoplasticStateVariables<G, Y>,
94    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
95        let first_piola_kirchhoff_tangent_stiffnesses = self
96            .deformation_gradients(nodal_coordinates)
97            .iter()
98            .zip(state_variables)
99            .map(|(deformation_gradient, state_variable)| {
100                let (deformation_gradient_p, _) = state_variable.into();
101                constitutive_model.first_piola_kirchhoff_tangent_stiffness(
102                    deformation_gradient,
103                    deformation_gradient_p,
104                )
105            })
106            .collect::<Result<FirstPiolaKirchhoffTangentStiffnessList<G>, _>>()
107            .map_err(|error| FiniteElementError::upstream(error, self))?;
108        Ok(first_piola_kirchhoff_tangent_stiffnesses
109            .iter()
110            .zip(
111                self.gradient_vectors()
112                    .iter()
113                    .zip(self.integration_weights()),
114            )
115            .map(
116                |(
117                    first_piola_kirchhoff_tangent_stiffness,
118                    (gradient_vectors, integration_weight),
119                )| {
120                    gradient_vectors
121                        .iter()
122                        .map(|gradient_vector_a| {
123                            gradient_vectors
124                                .iter()
125                                .map(|gradient_vector_b| {
126                                    first_piola_kirchhoff_tangent_stiffness
127                                        .contract_second_fourth_with_first(
128                                            gradient_vector_a,
129                                            gradient_vector_b,
130                                        )
131                                        * integration_weight
132                                })
133                                .collect()
134                        })
135                        .collect()
136                },
137            )
138            .sum())
139    }
140    fn state_variables_evolution(
141        &self,
142        constitutive_model: &C,
143        nodal_coordinates: &ElementNodalCoordinates<N>,
144        state_variables: &ViscoplasticStateVariables<G, Y>,
145    ) -> Result<ViscoplasticEvolution<G, Y>, FiniteElementError> {
146        self.deformation_gradients(nodal_coordinates)
147            .iter()
148            .zip(state_variables)
149            .map(|(deformation_gradient, state_variable)| {
150                constitutive_model.state_variables_evolution(deformation_gradient, state_variable)
151            })
152            .collect::<Result<ViscoplasticEvolution<G, Y>, _>>()
153            .map_err(|error| FiniteElementError::upstream(error, self))
154    }
155}