conspire/domain/vem/block/element/solid/hyperelastic/
mod.rs1use 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}