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}