conspire/domain/fem/block/element/solid/hyperelastic/
mod.rs1use crate::{
2 constitutive::{ConstitutiveError, solid::hyperelastic::Hyperelastic},
3 fem::block::element::{
4 Element, ElementNodalCoordinates, FiniteElementError, solid::elastic::ElasticFiniteElement,
5 surface::SurfaceElement,
6 },
7 math::{Scalar, Tensor},
8};
9
10pub trait HyperelasticFiniteElement<
11 C,
12 const G: usize,
13 const M: usize,
14 const N: usize,
15 const P: usize,
16> where
17 C: Hyperelastic,
18 Self: ElasticFiniteElement<C, G, M, N, P>,
19{
20 fn helmholtz_free_energy(
21 &self,
22 constitutive_model: &C,
23 nodal_coordinates: &ElementNodalCoordinates<N>,
24 ) -> Result<Scalar, FiniteElementError>;
25}
26
27impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
28 HyperelasticFiniteElement<C, G, 3, N, P> for Element<G, N, O>
29where
30 C: Hyperelastic,
31 Self: ElasticFiniteElement<C, G, 3, N, P>,
32{
33 fn helmholtz_free_energy(
34 &self,
35 constitutive_model: &C,
36 nodal_coordinates: &ElementNodalCoordinates<N>,
37 ) -> Result<Scalar, FiniteElementError> {
38 helmholtz_free_energy::<_, _, _, _, _, O, _>(self, constitutive_model, nodal_coordinates)
39 }
40}
41
42impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
43 HyperelasticFiniteElement<C, G, 2, N, P> for SurfaceElement<G, N, O>
44where
45 C: Hyperelastic,
46 Self: ElasticFiniteElement<C, G, 2, N, P>,
47{
48 fn helmholtz_free_energy(
49 &self,
50 constitutive_model: &C,
51 nodal_coordinates: &ElementNodalCoordinates<N>,
52 ) -> Result<Scalar, FiniteElementError> {
53 helmholtz_free_energy::<_, _, _, _, _, O, _>(self, constitutive_model, nodal_coordinates)
54 }
55}
56
57fn helmholtz_free_energy<
58 C,
59 F,
60 const G: usize,
61 const M: usize,
62 const N: usize,
63 const O: usize,
64 const P: usize,
65>(
66 element: &F,
67 constitutive_model: &C,
68 nodal_coordinates: &ElementNodalCoordinates<N>,
69) -> Result<Scalar, FiniteElementError>
70where
71 C: Hyperelastic,
72 F: ElasticFiniteElement<C, G, M, N, P>,
73{
74 match element
75 .deformation_gradients(nodal_coordinates)
76 .iter()
77 .zip(element.integration_weights())
78 .map(|(deformation_gradient, integration_weight)| {
79 Ok::<_, ConstitutiveError>(
80 constitutive_model.helmholtz_free_energy_density(deformation_gradient)?
81 * integration_weight,
82 )
83 })
84 .sum()
85 {
86 Ok(helmholtz_free_energy) => Ok(helmholtz_free_energy),
87 Err(error) => Err(FiniteElementError::Upstream(
88 format!("{error}"),
89 format!("{element:?}"),
90 )),
91 }
92}