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