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::ViscoplasticStateVariables,
8        },
9    },
10    math::{ContractSecondFourthIndicesWithFirstIndicesOf, 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> where
21    C: ElasticViscoplastic,
22    Self: SolidFiniteElement<G, M, N, P>,
23{
24    fn nodal_forces(
25        &self,
26        constitutive_model: &C,
27        nodal_coordinates: &ElementNodalCoordinates<N>,
28        state_variables: &ViscoplasticStateVariables<G>,
29    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError>;
30    fn nodal_stiffnesses(
31        &self,
32        constitutive_model: &C,
33        nodal_coordinates: &ElementNodalCoordinates<N>,
34        state_variables: &ViscoplasticStateVariables<G>,
35    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError>;
36    fn state_variables_evolution(
37        &self,
38        constitutive_model: &C,
39        nodal_coordinates: &ElementNodalCoordinates<N>,
40        state_variables: &ViscoplasticStateVariables<G>,
41    ) -> Result<ViscoplasticStateVariables<G>, FiniteElementError>;
42}
43
44impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
45    ElasticViscoplasticFiniteElement<C, G, 3, N, P> for Element<G, N, O>
46where
47    C: ElasticViscoplastic,
48    Self: SolidFiniteElement<G, 3, N, P>,
49{
50    fn nodal_forces(
51        &self,
52        constitutive_model: &C,
53        nodal_coordinates: &ElementNodalCoordinates<N>,
54        state_variables: &ViscoplasticStateVariables<G>,
55    ) -> Result<ElementNodalForcesSolid<N>, FiniteElementError> {
56        match self
57            .deformation_gradients(nodal_coordinates)
58            .iter()
59            .zip(state_variables)
60            .map(|(deformation_gradient, state_variable)| {
61                let (deformation_gradient_p, _) = state_variable.into();
62                constitutive_model
63                    .first_piola_kirchhoff_stress(deformation_gradient, deformation_gradient_p)
64            })
65            .collect::<Result<FirstPiolaKirchhoffStressList<G>, _>>()
66        {
67            Ok(first_piola_kirchhoff_stresses) => Ok(first_piola_kirchhoff_stresses
68                .iter()
69                .zip(
70                    self.gradient_vectors()
71                        .iter()
72                        .zip(self.integration_weights()),
73                )
74                .map(
75                    |(first_piola_kirchhoff_stress, (gradient_vectors, integration_weight))| {
76                        gradient_vectors
77                            .iter()
78                            .map(|gradient_vector| {
79                                (first_piola_kirchhoff_stress * gradient_vector)
80                                    * integration_weight
81                            })
82                            .collect()
83                    },
84                )
85                .sum()),
86            Err(error) => Err(FiniteElementError::Upstream(
87                format!("{error}"),
88                format!("{self:?}"),
89            )),
90        }
91    }
92    fn nodal_stiffnesses(
93        &self,
94        constitutive_model: &C,
95        nodal_coordinates: &ElementNodalCoordinates<N>,
96        state_variables: &ViscoplasticStateVariables<G>,
97    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
98        match self
99            .deformation_gradients(nodal_coordinates)
100            .iter()
101            .zip(state_variables)
102            .map(|(deformation_gradient, state_variable)| {
103                let (deformation_gradient_p, _) = state_variable.into();
104                constitutive_model.first_piola_kirchhoff_tangent_stiffness(
105                    deformation_gradient,
106                    deformation_gradient_p,
107                )
108            })
109            .collect::<Result<FirstPiolaKirchhoffTangentStiffnessList<G>, _>>()
110        {
111            Ok(first_piola_kirchhoff_tangent_stiffnesses) => {
112                Ok(first_piola_kirchhoff_tangent_stiffnesses
113                    .iter()
114                    .zip(
115                        self.gradient_vectors()
116                            .iter()
117                            .zip(self.integration_weights()),
118                    )
119                    .map(
120                        |(
121                            first_piola_kirchhoff_tangent_stiffness,
122                            (gradient_vectors, integration_weight),
123                        )| {
124                            gradient_vectors
125                                .iter()
126                                .map(|gradient_vector_a| {
127                                    gradient_vectors
128                                        .iter()
129                                        .map(|gradient_vector_b| {
130                                            first_piola_kirchhoff_tangent_stiffness
131                                            .contract_second_fourth_indices_with_first_indices_of(
132                                                gradient_vector_a,
133                                                gradient_vector_b,
134                                            )
135                                            * integration_weight
136                                        })
137                                        .collect()
138                                })
139                                .collect()
140                        },
141                    )
142                    .sum())
143            }
144            Err(error) => Err(FiniteElementError::Upstream(
145                format!("{error}"),
146                format!("{self:?}"),
147            )),
148        }
149    }
150    fn state_variables_evolution(
151        &self,
152        constitutive_model: &C,
153        nodal_coordinates: &ElementNodalCoordinates<N>,
154        state_variables: &ViscoplasticStateVariables<G>,
155    ) -> Result<ViscoplasticStateVariables<G>, FiniteElementError> {
156        match self
157            .deformation_gradients(nodal_coordinates)
158            .iter()
159            .zip(state_variables)
160            .map(|(deformation_gradient, state_variable)| {
161                constitutive_model.state_variables_evolution(deformation_gradient, state_variable)
162            })
163            .collect::<Result<ViscoplasticStateVariables<G>, _>>()
164        {
165            Ok(state_variables_evolution) => Ok(state_variables_evolution),
166            Err(error) => Err(FiniteElementError::Upstream(
167                format!("{error}"),
168                format!("{self:?}"),
169            )),
170        }
171    }
172}