Skip to main content

conspire/domain/fem/solid/hyperelastic_viscoplastic/
mod.rs

1use crate::{
2    fem::{
3        Blocks, ElasticViscoplasticAndElastic, ElementModel, ElementModelError, Elements, Model,
4        NodalCoordinates, NodalCoordinatesHistory,
5        block::{
6            finalize_node_neighbors, solid::elastic_viscoplastic::ElasticViscoplasticBCs,
7            solver_from_neighbors,
8        },
9        solid::{
10            NodalForcesSolid, NodalStiffnessesSolid,
11            elastic_viscoplastic::ElasticViscoplasticElements, hyperelastic::HyperelasticElements,
12        },
13    },
14    math::{
15        Derivative, Differentiate, Quantity, Tensor, TensorTuple, TensorVec,
16        integrate::{ExplicitDaeSecondOrderMinimize, IntegrationError},
17        optimize::SecondOrderOptimization,
18    },
19    mechanics::Times,
20    units::{Energy, Time},
21};
22
23pub trait HyperelasticViscoplasticElements<S, const D: usize>
24where
25    Self: ElasticViscoplasticElements<S, D>,
26    S: Differentiate,
27{
28    fn helmholtz_free_energy(
29        &self,
30        nodal_coordinates: &NodalCoordinates<D>,
31        state_variables: &S,
32    ) -> Result<Quantity<Energy>, ElementModelError>;
33}
34
35impl<B, S, const D: usize> HyperelasticViscoplasticElements<S, D> for Model<B, D>
36where
37    B: HyperelasticViscoplasticElements<S, D>,
38    S: Differentiate,
39{
40    fn helmholtz_free_energy(
41        &self,
42        nodal_coordinates: &NodalCoordinates<D>,
43        state_variables: &S,
44    ) -> Result<Quantity<Energy>, ElementModelError> {
45        self.blocks
46            .helmholtz_free_energy(nodal_coordinates, state_variables)
47    }
48}
49
50impl<B1, B2, S, const D: usize> HyperelasticViscoplasticElements<S, D>
51    for ElasticViscoplasticAndElastic<B1, B2>
52where
53    B1: HyperelasticViscoplasticElements<S, D>,
54    B2: HyperelasticElements<D>,
55    S: Differentiate,
56{
57    fn helmholtz_free_energy(
58        &self,
59        nodal_coordinates: &NodalCoordinates<D>,
60        state_variables: &S,
61    ) -> Result<Quantity<Energy>, ElementModelError> {
62        Ok(self
63            .0
64            .helmholtz_free_energy(nodal_coordinates, state_variables)?
65            + self.1.helmholtz_free_energy(nodal_coordinates)?)
66    }
67}
68
69impl<B1, B2, S1, S2, const D: usize> HyperelasticViscoplasticElements<TensorTuple<S1, S2>, D>
70    for Blocks<B1, B2>
71where
72    B1: HyperelasticViscoplasticElements<S1, D>,
73    B2: HyperelasticViscoplasticElements<S2, D>,
74    S1: Differentiate + Tensor,
75    S2: Differentiate + Tensor,
76    Derivative<S1>: Tensor,
77    Derivative<S2>: Tensor,
78{
79    fn helmholtz_free_energy(
80        &self,
81        nodal_coordinates: &NodalCoordinates<D>,
82        state_variables: &TensorTuple<S1, S2>,
83    ) -> Result<Quantity<Energy>, ElementModelError> {
84        Ok(self
85            .0
86            .helmholtz_free_energy(nodal_coordinates, &state_variables.0)?
87            + self
88                .1
89                .helmholtz_free_energy(nodal_coordinates, &state_variables.1)?)
90    }
91}
92
93pub trait SecondOrderMinimize<S, R, H, const D: usize>
94where
95    S: Differentiate + Tensor,
96    R: TensorVec<Item = Derivative<S>>,
97    H: TensorVec<Item = S>,
98{
99    fn minimize(
100        &self,
101        integrator: impl ExplicitDaeSecondOrderMinimize<
102            Quantity<Energy>,
103            NodalForcesSolid<D>,
104            NodalStiffnessesSolid<D>,
105            S,
106            NodalCoordinates<D>,
107            H,
108            NodalCoordinatesHistory<D>,
109            R,
110        >,
111        solver: impl SecondOrderOptimization<
112            Quantity<Energy>,
113            NodalForcesSolid<D>,
114            NodalStiffnessesSolid<D>,
115            NodalCoordinates<D>,
116        >,
117        time: &[Quantity<Time>],
118        bcs: ElasticViscoplasticBCs,
119    ) -> Result<(Times, NodalCoordinatesHistory<D>, H), IntegrationError>;
120}
121
122impl<B, S, R, H, const D: usize> SecondOrderMinimize<S, R, H, D> for Model<B, D>
123where
124    B: HyperelasticViscoplasticElements<S, D>,
125    S: Differentiate + Tensor,
126    R: TensorVec<Item = Derivative<S>>,
127    H: TensorVec<Item = S>,
128{
129    fn minimize(
130        &self,
131        integrator: impl ExplicitDaeSecondOrderMinimize<
132            Quantity<Energy>,
133            NodalForcesSolid<D>,
134            NodalStiffnessesSolid<D>,
135            S,
136            NodalCoordinates<D>,
137            H,
138            NodalCoordinatesHistory<D>,
139            R,
140        >,
141        solver: impl SecondOrderOptimization<
142            Quantity<Energy>,
143            NodalForcesSolid<D>,
144            NodalStiffnessesSolid<D>,
145            NodalCoordinates<D>,
146        >,
147        time: &[Quantity<Time>],
148        bcs: ElasticViscoplasticBCs,
149    ) -> Result<(Times, NodalCoordinatesHistory<D>, H), IntegrationError> {
150        let mut neighbors = vec![Vec::new(); self.coordinates().len()];
151        self.node_neighbors(&mut neighbors);
152        finalize_node_neighbors(&mut neighbors);
153        let sparse = solver_from_neighbors(&neighbors, &bcs(time[0]), D, true);
154        let (time_history, state_variables_history, _, nodal_coordinates_history) = integrator
155            .integrate(
156                |_: Quantity<Time>,
157                 state_variables: &S,
158                 nodal_coordinates: &NodalCoordinates<D>| {
159                    Ok(self
160                        .blocks
161                        .state_variables_evolution(nodal_coordinates, state_variables)?)
162                },
163                |_: Quantity<Time>,
164                 state_variables: &S,
165                 nodal_coordinates: &NodalCoordinates<D>| {
166                    Ok(self
167                        .blocks
168                        .helmholtz_free_energy(nodal_coordinates, state_variables)?)
169                },
170                |_: Quantity<Time>,
171                 state_variables: &S,
172                 nodal_coordinates: &NodalCoordinates<D>| {
173                    Ok(self
174                        .blocks
175                        .nodal_forces(nodal_coordinates, state_variables)?)
176                },
177                |_: Quantity<Time>,
178                 state_variables: &S,
179                 nodal_coordinates: &NodalCoordinates<D>| {
180                    Ok(self
181                        .blocks
182                        .nodal_stiffnesses(nodal_coordinates, state_variables)?)
183                },
184                solver,
185                time,
186                (
187                    self.blocks.initial_state(),
188                    self.coordinates().clone().into(),
189                ),
190                bcs,
191                Some(sparse),
192            )?;
193        Ok((
194            time_history,
195            nodal_coordinates_history,
196            state_variables_history,
197        ))
198    }
199}