conspire/domain/vem/block/element/solid/hyperelastic/
mod.rs

1use crate::{
2    constitutive::{ConstitutiveError, solid::hyperelastic::Hyperelastic},
3    fem::block::element::solid::hyperelastic::HyperelasticFiniteElement,
4    math::{Scalar, Tensor},
5    vem::block::element::{
6        Element, ElementNodalCoordinates, VirtualElement, VirtualElementError,
7        solid::{SolidVirtualElement, elastic::ElasticVirtualElement},
8    },
9};
10
11pub trait HyperelasticVirtualElement<C>
12where
13    C: Hyperelastic,
14    Self: ElasticVirtualElement<C>,
15{
16    fn helmholtz_free_energy<'a>(
17        &'a self,
18        constitutive_model: &'a C,
19        nodal_coordinates: ElementNodalCoordinates<'a>,
20    ) -> Result<Scalar, VirtualElementError>;
21}
22
23impl<C> HyperelasticVirtualElement<C> for Element
24where
25    C: Hyperelastic,
26    Self: ElasticVirtualElement<C>,
27{
28    fn helmholtz_free_energy<'a>(
29        &'a self,
30        constitutive_model: &'a C,
31        nodal_coordinates: ElementNodalCoordinates<'a>,
32    ) -> Result<Scalar, VirtualElementError> {
33        match self
34            .tetrahedra()
35            .iter()
36            .zip(self.tetrahedra_coordinates(&nodal_coordinates).iter())
37            .map(|(tetrahedron, tetrahedron_coordinates)| {
38                tetrahedron.helmholtz_free_energy(constitutive_model, tetrahedron_coordinates)
39            })
40            .sum::<Result<Scalar, _>>()
41        {
42            Ok(tetrahedra_energy) => {
43                match self
44                    .deformation_gradients(nodal_coordinates)
45                    .iter()
46                    .zip(self.integration_weights())
47                    .map(|(deformation_gradient, integration_weight)| {
48                        Ok::<_, ConstitutiveError>(
49                            constitutive_model
50                                .helmholtz_free_energy_density(deformation_gradient)?
51                                * integration_weight,
52                        )
53                    })
54                    .sum::<Result<Scalar, _>>()
55                {
56                    Ok(polyhedron_energy) => Ok(polyhedron_energy * (1.0 - self.stabilization())
57                        + tetrahedra_energy * self.stabilization()),
58                    Err(error) => Err(VirtualElementError::Upstream(
59                        format!("{error}"),
60                        format!("{self:?}"),
61                    )),
62                }
63            }
64            Err(error) => Err(VirtualElementError::Upstream(
65                format!("{error}"),
66                format!("{self:?}"),
67            )),
68        }
69    }
70}