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::{ViscoplasticEvolution, ViscoplasticStateVariables},
8 },
9 },
10 math::{ContractSecondFourthWithFirst, Differentiate, 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: Differentiate + 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<ViscoplasticEvolution<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<3, G, N, O>
48where
49 C: ElasticViscoplastic<Y>,
50 Self: SolidFiniteElement<G, 3, N, P>,
51 Y: Differentiate + 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 let first_piola_kirchhoff_stresses = 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 .map_err(|error| FiniteElementError::upstream(error, self))?;
70 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) * integration_weight
83 })
84 .collect()
85 },
86 )
87 .sum())
88 }
89 fn nodal_stiffnesses(
90 &self,
91 constitutive_model: &C,
92 nodal_coordinates: &ElementNodalCoordinates<N>,
93 state_variables: &ViscoplasticStateVariables<G, Y>,
94 ) -> Result<ElementNodalStiffnessesSolid<N>, FiniteElementError> {
95 let first_piola_kirchhoff_tangent_stiffnesses = self
96 .deformation_gradients(nodal_coordinates)
97 .iter()
98 .zip(state_variables)
99 .map(|(deformation_gradient, state_variable)| {
100 let (deformation_gradient_p, _) = state_variable.into();
101 constitutive_model.first_piola_kirchhoff_tangent_stiffness(
102 deformation_gradient,
103 deformation_gradient_p,
104 )
105 })
106 .collect::<Result<FirstPiolaKirchhoffTangentStiffnessList<G>, _>>()
107 .map_err(|error| FiniteElementError::upstream(error, self))?;
108 Ok(first_piola_kirchhoff_tangent_stiffnesses
109 .iter()
110 .zip(
111 self.gradient_vectors()
112 .iter()
113 .zip(self.integration_weights()),
114 )
115 .map(
116 |(
117 first_piola_kirchhoff_tangent_stiffness,
118 (gradient_vectors, integration_weight),
119 )| {
120 gradient_vectors
121 .iter()
122 .map(|gradient_vector_a| {
123 gradient_vectors
124 .iter()
125 .map(|gradient_vector_b| {
126 first_piola_kirchhoff_tangent_stiffness
127 .contract_second_fourth_with_first(
128 gradient_vector_a,
129 gradient_vector_b,
130 )
131 * integration_weight
132 })
133 .collect()
134 })
135 .collect()
136 },
137 )
138 .sum())
139 }
140 fn state_variables_evolution(
141 &self,
142 constitutive_model: &C,
143 nodal_coordinates: &ElementNodalCoordinates<N>,
144 state_variables: &ViscoplasticStateVariables<G, Y>,
145 ) -> Result<ViscoplasticEvolution<G, Y>, FiniteElementError> {
146 self.deformation_gradients(nodal_coordinates)
147 .iter()
148 .zip(state_variables)
149 .map(|(deformation_gradient, state_variable)| {
150 constitutive_model.state_variables_evolution(deformation_gradient, state_variable)
151 })
152 .collect::<Result<ViscoplasticEvolution<G, Y>, _>>()
153 .map_err(|error| FiniteElementError::upstream(error, self))
154 }
155}