conspire/domain/vem/block/element/solid/hyperelastic/
mod.rs1use crate::math::Quantity;
2use crate::{
3 constitutive::{ConstitutiveError, solid::hyperelastic::Hyperelastic},
4 domain::block::element::solid::hyperelastic::HyperelasticElement,
5 math::Tensor,
6 units::Energy,
7 vem::block::element::{
8 Element, ElementNodalCoordinates, VirtualElement, VirtualElementError,
9 solid::{SolidElement, elastic::ElasticVirtualElement},
10 },
11};
12
13pub trait HyperelasticVirtualElement<C>
14where
15 C: Hyperelastic,
16 Self: ElasticVirtualElement<C> + HyperelasticElement<C>,
17{
18}
19
20impl<T, C> HyperelasticVirtualElement<C> for T
21where
22 C: Hyperelastic,
23 T: ElasticVirtualElement<C> + HyperelasticElement<C>,
24{
25}
26
27impl<C> HyperelasticElement<C> for Element
28where
29 C: Hyperelastic,
30{
31 fn helmholtz_free_energy(
32 &self,
33 constitutive_model: &C,
34 nodal_coordinates: &ElementNodalCoordinates,
35 ) -> Result<Quantity<Energy>, VirtualElementError> {
36 let tetrahedra_energy = self
37 .tetrahedra()
38 .iter()
39 .zip(self.tetrahedra_coordinates(nodal_coordinates).iter())
40 .map(|(tetrahedron, tetrahedron_coordinates)| {
41 tetrahedron.helmholtz_free_energy(constitutive_model, tetrahedron_coordinates)
42 })
43 .sum::<Result<Quantity<Energy>, _>>()
44 .map_err(|error| self.upstream(error))?;
45 let polyhedron_energy = self
46 .deformation_gradients(nodal_coordinates)
47 .iter()
48 .zip(self.integration_weights())
49 .map(|(deformation_gradient, integration_weight)| {
50 Ok::<_, ConstitutiveError>(
51 constitutive_model.helmholtz_free_energy_density(deformation_gradient)?
52 * integration_weight,
53 )
54 })
55 .sum::<Result<Quantity<Energy>, _>>()
56 .map_err(|error| self.upstream(error))?;
57 Ok(polyhedron_energy * (1.0 - self.stabilization())
58 + tetrahedra_energy * self.stabilization())
59 }
60}