Skip to main content

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

1use 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}