conspire/domain/fem/solid/hyperelastic/
mod.rs1use crate::{
2 fem::{
3 Blocks, ElementModel, ElementModelError, Elements, FirstOrderMinimize, Model,
4 NodalCoordinates, SecondOrderMinimize,
5 block::{band_from_neighbors, finalize_node_neighbors},
6 solid::{NodalForcesSolid, NodalStiffnessesSolid, elastic::ElasticElements},
7 },
8 math::{
9 Scalar, Tensor,
10 optimize::{
11 EqualityConstraint, FirstOrderOptimization, OptimizationError, SecondOrderOptimization,
12 },
13 },
14};
15
16pub trait HyperelasticElements<const D: usize>
17where
18 Self: ElasticElements<D>,
19{
20 fn helmholtz_free_energy(
21 &self,
22 nodal_coordinates: &NodalCoordinates<D>,
23 ) -> Result<Scalar, ElementModelError>;
24}
25
26impl<B, const D: usize> HyperelasticElements<D> for Model<B, D>
27where
28 B: HyperelasticElements<D>,
29{
30 fn helmholtz_free_energy(
31 &self,
32 nodal_coordinates: &NodalCoordinates<D>,
33 ) -> Result<Scalar, ElementModelError> {
34 self.blocks.helmholtz_free_energy(nodal_coordinates)
35 }
36}
37
38impl<B1, B2, const D: usize> HyperelasticElements<D> for Blocks<B1, B2>
39where
40 B1: HyperelasticElements<D>,
41 B2: HyperelasticElements<D>,
42{
43 fn helmholtz_free_energy(
44 &self,
45 nodal_coordinates: &NodalCoordinates<D>,
46 ) -> Result<Scalar, ElementModelError> {
47 Ok(self.0.helmholtz_free_energy(nodal_coordinates)?
48 + self.1.helmholtz_free_energy(nodal_coordinates)?)
49 }
50}
51
52impl<B, const D: usize> FirstOrderMinimize<Scalar, NodalCoordinates<D>> for Model<B, D>
53where
54 B: HyperelasticElements<D>,
55{
56 fn minimize(
57 &self,
58 equality_constraint: EqualityConstraint,
59 solver: impl FirstOrderOptimization<Scalar, NodalCoordinates<D>>,
60 ) -> Result<NodalCoordinates<D>, OptimizationError> {
61 solver.minimize(
62 |nodal_coordinates: &NodalCoordinates<D>| {
63 Ok(self.helmholtz_free_energy(nodal_coordinates)?)
64 },
65 |nodal_coordinates: &NodalCoordinates<D>| Ok(self.nodal_forces(nodal_coordinates)?),
66 self.coordinates().clone().into(),
67 equality_constraint,
68 )
69 }
70}
71
72impl<B, const D: usize>
73 SecondOrderMinimize<Scalar, NodalForcesSolid<D>, NodalStiffnessesSolid<D>, NodalCoordinates<D>>
74 for Model<B, D>
75where
76 B: HyperelasticElements<D>,
77{
78 fn minimize(
79 &self,
80 equality_constraint: EqualityConstraint,
81 solver: impl SecondOrderOptimization<
82 Scalar,
83 NodalForcesSolid<D>,
84 NodalStiffnessesSolid<D>,
85 NodalCoordinates<D>,
86 >,
87 ) -> Result<NodalCoordinates<D>, OptimizationError> {
88 let mut neighbors = vec![Vec::new(); self.coordinates().len()];
89 self.node_neighbors(&mut neighbors);
90 finalize_node_neighbors(&mut neighbors);
91 let banded = band_from_neighbors(&neighbors, &equality_constraint, D);
92 solver.minimize(
93 |nodal_coordinates: &NodalCoordinates<D>| {
94 Ok(self.helmholtz_free_energy(nodal_coordinates)?)
95 },
96 |nodal_coordinates: &NodalCoordinates<D>| Ok(self.nodal_forces(nodal_coordinates)?),
97 |nodal_coordinates: &NodalCoordinates<D>| {
98 Ok(self.nodal_stiffnesses(nodal_coordinates)?)
99 },
100 self.coordinates().clone().into(),
101 equality_constraint,
102 Some(banded),
103 )
104 }
105}