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    Y,
21> where
22    C: ElasticViscoplastic<Y>,
23    Self: SolidFiniteElement<G, M, N, P>,
24    Y: 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<ViscoplasticStateVariables<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<G, N, O>
48where
49    C: ElasticViscoplastic<Y>,
50    Self: SolidFiniteElement<G, 3, N, P>,
51    Y: 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        match 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        {
70            Ok(first_piola_kirchhoff_stresses) => 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)
83                                    * integration_weight
84                            })
85                            .collect()
86                    },
87                )
88                .sum()),
89            Err(error) => Err(FiniteElementError::Upstream(
90                format!("{error}"),
91                format!("{self:?}"),
92            )),
93        }
94    }
95    fn nodal_stiffnesses(
96        &self,
97        constitutive_model: &C,
98        nodal_coordinates: &ElementNodalCoordinates<N>,
99        state_variables: &ViscoplasticStateVariables<G, Y>,
100    ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
101        match self
102            .deformation_gradients(nodal_coordinates)
103            .iter()
104            .zip(state_variables)
105            .map(|(deformation_gradient, state_variable)| {
106                let (deformation_gradient_p, _) = state_variable.into();
107                constitutive_model.first_piola_kirchhoff_tangent_stiffness(
108                    deformation_gradient,
109                    deformation_gradient_p,
110                )
111            })
112            .collect::<Result<FirstPiolaKirchhoffTangentStiffnessList<G>, _>>()
113        {
114            Ok(first_piola_kirchhoff_tangent_stiffnesses) => {
115                Ok(first_piola_kirchhoff_tangent_stiffnesses
116                    .iter()
117                    .zip(
118                        self.gradient_vectors()
119                            .iter()
120                            .zip(self.integration_weights()),
121                    )
122                    .map(
123                        |(
124                            first_piola_kirchhoff_tangent_stiffness,
125                            (gradient_vectors, integration_weight),
126                        )| {
127                            gradient_vectors
128                                .iter()
129                                .map(|gradient_vector_a| {
130                                    gradient_vectors
131                                        .iter()
132                                        .map(|gradient_vector_b| {
133                                            first_piola_kirchhoff_tangent_stiffness
134                                            .contract_second_fourth_indices_with_first_indices_of(
135                                                gradient_vector_a,
136                                                gradient_vector_b,
137                                            )
138                                            * integration_weight
139                                        })
140                                        .collect()
141                                })
142                                .collect()
143                        },
144                    )
145                    .sum())
146            }
147            Err(error) => Err(FiniteElementError::Upstream(
148                format!("{error}"),
149                format!("{self:?}"),
150            )),
151        }
152    }
153    fn state_variables_evolution(
154        &self,
155        constitutive_model: &C,
156        nodal_coordinates: &ElementNodalCoordinates<N>,
157        state_variables: &ViscoplasticStateVariables<G, Y>,
158    ) -> Result<ViscoplasticStateVariables<G, Y>, FiniteElementError> {
159        match self
160            .deformation_gradients(nodal_coordinates)
161            .iter()
162            .zip(state_variables)
163            .map(|(deformation_gradient, state_variable)| {
164                constitutive_model.state_variables_evolution(deformation_gradient, state_variable)
165            })
166            .collect::<Result<ViscoplasticStateVariables<G, Y>, _>>()
167        {
168            Ok(state_variables_evolution) => Ok(state_variables_evolution),
169            Err(error) => Err(FiniteElementError::Upstream(
170                format!("{error}"),
171                format!("{self:?}"),
172            )),
173        }
174    }
175}