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