Skip to main content

conspire/domain/fem/block/solid/elastic_viscoplastic/
mod.rs

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}