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