1use crate::{
2 constitutive::{
3 fluid::viscoplastic::ViscoplasticStateVariables as PointStateVariables,
4 solid::elastic_viscoplastic::ElasticViscoplastic,
5 },
6 fem::{
7 ElementModelError, NodalCoordinates,
8 block::{
9 Block,
10 element::{
11 FiniteElementError,
12 solid::{
13 SolidFiniteElement, elastic_viscoplastic::ElasticViscoplasticFiniteElement,
14 },
15 },
16 },
17 solid::{
18 NodalForcesSolid, NodalStiffnessesSolid,
19 elastic_viscoplastic::{ElasticViscoplasticDaeElements, ElasticViscoplasticElements},
20 },
21 },
22 math::{
23 Derivative, Differentiable, Quantity, Tensor, TensorVec, TensorVector,
24 integrate::{EvolvedIncrement, Integrable, List, StateEvolution},
25 },
26 mechanics::DeformationGradient,
27 units::Time,
28};
29use std::array::from_fn;
30
31pub use crate::domain::{
32 block::solid::viscoplastic::{
33 ViscoplasticEvolution, ViscoplasticStateVariables, ViscoplasticStateVariablesHistory,
34 },
35 solid::elastic_viscoplastic::ElasticViscoplasticBCs,
36};
37
38impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize, Y>
39 ElasticViscoplasticElements<ViscoplasticStateVariables<G, Y>, 3> for Block<C, F, G, M, N, P>
40where
41 C: ElasticViscoplastic<Y>,
42 F: ElasticViscoplasticFiniteElement<C, G, M, N, P, Y>,
43 Y: Differentiable + Tensor,
44{
45 fn initial_state(&self) -> ViscoplasticStateVariables<G, Y> {
46 self.elements()
47 .iter()
48 .map(|_| from_fn(|_| self.constitutive_model().initial_state()).into())
49 .collect()
50 }
51 fn nodal_forces_into(
52 &self,
53 nodal_coordinates: &NodalCoordinates<3>,
54 state_variables: &ViscoplasticStateVariables<G, Y>,
55 nodal_forces: &mut NodalForcesSolid<3>,
56 ) -> Result<(), ElementModelError> {
57 self.elements()
58 .iter()
59 .zip(self.connectivity())
60 .zip(state_variables)
61 .try_for_each(|((element, nodes), state_variables_element)| {
62 element
63 .nodal_forces(
64 self.constitutive_model(),
65 &Self::element_coordinates(nodal_coordinates, nodes),
66 state_variables_element,
67 )?
68 .into_iter()
69 .zip(nodes)
70 .for_each(|(nodal_force, &node)| nodal_forces[node] += nodal_force);
71 Ok::<(), FiniteElementError>(())
72 })
73 .map_err(|error| ElementModelError::upstream(error, self))
74 }
75 fn nodal_stiffnesses_into(
76 &self,
77 nodal_coordinates: &NodalCoordinates<3>,
78 state_variables: &ViscoplasticStateVariables<G, Y>,
79 nodal_stiffnesses: &mut NodalStiffnessesSolid<3>,
80 ) -> Result<(), ElementModelError> {
81 self.elements()
82 .iter()
83 .zip(self.connectivity())
84 .zip(state_variables)
85 .try_for_each(|((element, nodes), state_variables_element)| {
86 element
87 .nodal_stiffnesses(
88 self.constitutive_model(),
89 &Self::element_coordinates(nodal_coordinates, nodes),
90 state_variables_element,
91 )?
92 .into_iter()
93 .zip(nodes)
94 .for_each(|(object, &node_a)| {
95 object
96 .into_iter()
97 .zip(nodes)
98 .for_each(|(nodal_stiffness, &node_b)| {
99 nodal_stiffnesses[node_a][node_b] += nodal_stiffness
100 })
101 });
102 Ok::<(), FiniteElementError>(())
103 })
104 .map_err(|error| ElementModelError::upstream(error, self))
105 }
106 fn state_variables_evolution(
107 &self,
108 nodal_coordinates: &NodalCoordinates<3>,
109 state_variables: &ViscoplasticStateVariables<G, Y>,
110 ) -> Result<ViscoplasticEvolution<G, Y>, ElementModelError> {
111 self.elements()
112 .iter()
113 .zip(self.connectivity())
114 .zip(state_variables)
115 .map(|((element, nodes), element_state_variables)| {
116 element.state_variables_evolution(
117 self.constitutive_model(),
118 &Self::element_coordinates(nodal_coordinates, nodes),
119 element_state_variables,
120 )
121 })
122 .collect::<Result<_, FiniteElementError>>()
123 .map_err(|error| ElementModelError::upstream(error, self))
124 }
125}
126
127fn flatten_state<const G: usize, Y>(
128 state: &ViscoplasticStateVariables<G, Y>,
129) -> TensorVector<PointStateVariables<Y>>
130where
131 Y: Clone + Tensor,
132{
133 state
134 .iter()
135 .flat_map(|element_state| element_state.iter().cloned())
136 .collect()
137}
138
139fn unflatten_state<const G: usize, Y>(
140 flat: &TensorVector<PointStateVariables<Y>>,
141) -> ViscoplasticStateVariables<G, Y>
142where
143 Y: Clone + Tensor,
144{
145 flat.as_slice()
146 .chunks(G)
147 .map(|chunk| chunk.iter().cloned().collect())
148 .collect()
149}
150
151impl<C, F, const G: usize, const N: usize, const P: usize, Y> ElasticViscoplasticDaeElements<Y, 3>
152 for Block<C, F, G, 3, N, P>
153where
154 F: SolidFiniteElement<G, 3, N, P> + ElasticViscoplasticFiniteElement<C, G, 3, N, P, Y>,
155 Y: Clone + Differentiable<Time> + Tensor,
156 C: ElasticViscoplastic<Y>
157 + StateEvolution<
158 Time,
159 Y,
160 Drive = DeformationGradient,
161 Field: Integrable<Point = PointStateVariables<Y>>,
162 >,
163 EvolvedIncrement<C, Time, Y>: Clone + Differentiable<Time>,
164 TensorVector<PointStateVariables<Y>>: Tensor<Item = PointStateVariables<Y>>,
165 TensorVector<EvolvedIncrement<C, Time, Y>>: Tensor<Item = EvolvedIncrement<C, Time, Y>>,
166 ViscoplasticStateVariables<G, Y>: Clone + Differentiable + Tensor,
167 ViscoplasticStateVariablesHistory<G, Y>: TensorVec<Item = ViscoplasticStateVariables<G, Y>>,
168{
169 type Field = List<<C as StateEvolution<Time, Y>>::Field>;
170 type State = ViscoplasticStateVariables<G, Y>;
171 type History = ViscoplasticStateVariablesHistory<G, Y>;
172 fn flatten(state: &ViscoplasticStateVariables<G, Y>) -> TensorVector<PointStateVariables<Y>> {
173 flatten_state::<G, Y>(state)
174 }
175 fn unflatten(flat: &TensorVector<PointStateVariables<Y>>) -> ViscoplasticStateVariables<G, Y> {
176 unflatten_state::<G, Y>(flat)
177 }
178 fn dae_rate(
179 &self,
180 t: Quantity<Time>,
181 nodal_coordinates: &NodalCoordinates<3>,
182 flat: &TensorVector<PointStateVariables<Y>>,
183 ) -> Result<TensorVector<Derivative<EvolvedIncrement<C, Time, Y>, Time>>, ElementModelError>
184 {
185 let model = self.constitutive_model();
186 self.elements()
187 .iter()
188 .zip(self.connectivity())
189 .enumerate()
190 .flat_map(|(e, (element, nodes))| {
191 let element_coordinates = Self::element_coordinates(nodal_coordinates, nodes);
192 element
193 .deformation_gradients(&element_coordinates)
194 .iter()
195 .enumerate()
196 .map(|(g, deformation_gradient)| {
197 model.state_rate(t, deformation_gradient, &flat[e * G + g])
198 })
199 .collect::<Vec<_>>()
200 })
201 .collect::<Result<_, String>>()
202 .map_err(|error| ElementModelError::upstream(error, self))
203 }
204}