conspire/domain/fem/solid/hyperelastic/internal_variables/
mod.rs1use crate::{
2 fem::{
3 ElementModel, ElementModelError, Elements, Model, NodalCoordinates,
4 block::{finalize_node_neighbors, solver_from_neighbors},
5 solid::{
6 NodalForcesSolid, NodalStiffnessesSolid,
7 elastic::internal_variables::{
8 CarriedInternalVariables, ElasticIVElements, InternalVariablesField,
9 SolvedInternalVariables,
10 },
11 },
12 },
13 math::{
14 Quantity, Scalar, Tensor, Vector,
15 optimize::{
16 EqualityConstraint, OptimizationError, SecondOrderOptimization,
17 SecondOrderOptimizationIncremental, SolveStrategy,
18 },
19 },
20 units::Energy,
21};
22
23pub trait HyperelasticIVElements<const G: usize, V, const D: usize>
24where
25 Self: ElasticIVElements<G, V, D>,
26 V: Tensor,
27{
28 fn helmholtz_free_energy(
29 &self,
30 nodal_coordinates: &NodalCoordinates<D>,
31 internal_variables: &InternalVariablesField<G, V>,
32 ) -> Result<Quantity<Energy>, ElementModelError>;
33}
34
35impl<B, const G: usize, V, const D: usize> HyperelasticIVElements<G, V, D> for Model<B, D>
36where
37 B: HyperelasticIVElements<G, V, D>,
38 V: Tensor,
39{
40 fn helmholtz_free_energy(
41 &self,
42 nodal_coordinates: &NodalCoordinates<D>,
43 internal_variables: &InternalVariablesField<G, V>,
44 ) -> Result<Quantity<Energy>, ElementModelError> {
45 self.blocks
46 .helmholtz_free_energy(nodal_coordinates, internal_variables)
47 }
48}
49
50pub trait SecondOrderMinimizeIV<const G: usize, V, const D: usize>
53where
54 V: Tensor,
55{
56 fn minimize(
57 &self,
58 equality_constraint: EqualityConstraint,
59 solver: impl SecondOrderOptimization<
60 Quantity<Energy>,
61 NodalForcesSolid<D>,
62 NodalStiffnessesSolid<D>,
63 NodalCoordinates<D>,
64 > + SecondOrderOptimizationIncremental<
65 Quantity<Energy>,
66 NodalForcesSolid<D>,
67 NodalStiffnessesSolid<D>,
68 NodalCoordinates<D>,
69 >,
70 strategy: SolveStrategy,
71 ) -> Result<NodalCoordinates<D>, OptimizationError>;
72}
73
74impl<B, const G: usize, V, const D: usize> SecondOrderMinimizeIV<G, V, D> for Model<B, D>
75where
76 B: HyperelasticIVElements<G, V, D>,
77 V: Tensor,
78{
79 fn minimize(
80 &self,
81 equality_constraint: EqualityConstraint,
82 solver: impl SecondOrderOptimization<
83 Quantity<Energy>,
84 NodalForcesSolid<D>,
85 NodalStiffnessesSolid<D>,
86 NodalCoordinates<D>,
87 > + SecondOrderOptimizationIncremental<
88 Quantity<Energy>,
89 NodalForcesSolid<D>,
90 NodalStiffnessesSolid<D>,
91 NodalCoordinates<D>,
92 >,
93 strategy: SolveStrategy,
94 ) -> Result<NodalCoordinates<D>, OptimizationError> {
95 let initial = self.internal_variables_initial();
96 let mut neighbors = vec![Vec::new(); self.coordinates().len()];
97 self.node_neighbors(&mut neighbors);
98 finalize_node_neighbors(&mut neighbors);
99 let sparse = solver_from_neighbors(&neighbors, &equality_constraint, D, true);
105 match strategy {
106 SolveStrategy::Condensed(ref local_solver) => {
112 let solved = SolvedInternalVariables::new(self, local_solver, initial);
113 solver.minimize(
114 |nodal_coordinates: &NodalCoordinates<D>| {
115 Ok(self.helmholtz_free_energy(
116 nodal_coordinates,
117 &solved.at(nodal_coordinates)?,
118 )?)
119 },
120 |nodal_coordinates: &NodalCoordinates<D>| {
121 Ok(self.nodal_forces(nodal_coordinates, &solved.at(nodal_coordinates)?)?)
122 },
123 |nodal_coordinates: &NodalCoordinates<D>| {
124 Ok(self
125 .nodal_stiffnesses(nodal_coordinates, &solved.at(nodal_coordinates)?)?)
126 },
127 self.coordinates().clone().into(),
128 equality_constraint,
129 Some(sparse),
130 )
131 }
132 SolveStrategy::Monolithic { elimination: true } => {
140 let carried = CarriedInternalVariables::new(self, initial);
141 solver.minimize_incremental(
142 |nodal_coordinates: &NodalCoordinates<D>| {
143 Ok(self.helmholtz_free_energy(nodal_coordinates, &carried.stepped())?)
144 },
145 |nodal_coordinates: &NodalCoordinates<D>| {
146 Ok(self.nodal_forces_eliminated(nodal_coordinates, &carried.stepped())?)
147 },
148 |nodal_coordinates: &NodalCoordinates<D>| {
149 Ok(self.nodal_stiffnesses(nodal_coordinates, &carried.stepped())?)
150 },
151 |nodal_coordinates: &NodalCoordinates<D>,
152 decrement: &Vector,
153 step: Scalar,
154 commit: bool| {
155 Ok(carried.step(nodal_coordinates, decrement, step, commit)?)
156 },
157 self.coordinates().clone().into(),
158 equality_constraint,
159 Some(sparse),
160 )
161 }
162 SolveStrategy::Monolithic { elimination: false } => unimplemented!(
163 "The internal variables must be unknowns of the solver to be solved with it."
164 ),
165 }
166 }
167}