conspire/domain/fem/block/element/solid/hyperelastic/internal_variables/
mod.rs1use crate::units::{Dimensionless, UnitDiv};
2use std::ops::{Div, Mul};
3
4use crate::{
5 constitutive::{ConstitutiveError, solid::hyperelastic::internal_variables::HyperelasticIV},
6 fem::block::element::{
7 Element, ElementNodalCoordinates, FiniteElement, FiniteElementError,
8 solid::{
9 SolidFiniteElement,
10 elastic::internal_variables::{ElasticIVFiniteElement, InternalVariables},
11 },
12 },
13 math::{Erase, Jacobian, Matrix, Quantity, Scalar, Solution, Tensor, Vector},
14 units::Energy,
15};
16
17pub trait HyperelasticIVFiniteElement<
18 C,
19 const G: usize,
20 const M: usize,
21 const N: usize,
22 const P: usize,
23 V,
24 E,
25> where
26 C: HyperelasticIV<V>,
27 C::Residual: Erase<Erased = E>,
28 Self: ElasticIVFiniteElement<C, G, M, N, P, V, E>,
29 E: Tensor,
30 for<'a> &'a C::Residual: Div<C::TangentVv, Output = V>,
31 for<'a> &'a V: Mul<Quantity<Dimensionless>, Output = V> + Mul<Scalar, Output = V>,
32 for<'a> &'a Matrix: Mul<&'a V, Output = Vector>,
33 V: Erase<Erased = E> + Jacobian + Solution,
34 <V as Tensor>::Unit: UnitDiv<<V as Tensor>::Unit, Output = Dimensionless>,
35{
36 fn helmholtz_free_energy(
37 &self,
38 constitutive_model: &C,
39 nodal_coordinates: &ElementNodalCoordinates<N>,
40 internal_variables: &InternalVariables<G, V>,
41 ) -> Result<Quantity<Energy>, FiniteElementError>;
42}
43
44impl<C, const G: usize, const N: usize, const O: usize, const P: usize, V, E>
45 HyperelasticIVFiniteElement<C, G, 3, N, P, V, E> for Element<3, G, N, O>
46where
47 C: HyperelasticIV<V>,
48 C::Residual: Erase<Erased = E>,
49 Self: ElasticIVFiniteElement<C, G, 3, N, P, V, E> + SolidFiniteElement<G, 3, N, P>,
50 E: Tensor,
51 for<'a> &'a C::Residual: Div<C::TangentVv, Output = V>,
52 for<'a> &'a V: Mul<Quantity<Dimensionless>, Output = V> + Mul<Scalar, Output = V>,
53 for<'a> &'a Matrix: Mul<&'a V, Output = Vector>,
54 V: Erase<Erased = E> + Jacobian + Solution,
55 <V as Tensor>::Unit: UnitDiv<<V as Tensor>::Unit, Output = Dimensionless>,
56{
57 fn helmholtz_free_energy(
58 &self,
59 constitutive_model: &C,
60 nodal_coordinates: &ElementNodalCoordinates<N>,
61 internal_variables: &InternalVariables<G, V>,
62 ) -> Result<Quantity<Energy>, FiniteElementError> {
63 self.deformation_gradients(nodal_coordinates)
64 .iter()
65 .zip(internal_variables)
66 .zip(self.integration_weights())
67 .map(
68 |((deformation_gradient, internal_variables_point), integration_weight)| {
69 Ok(constitutive_model.helmholtz_free_energy_density(
70 deformation_gradient,
71 internal_variables_point,
72 )? * integration_weight)
73 },
74 )
75 .sum::<Result<Quantity<Energy>, ConstitutiveError>>()
76 .map_err(|error| FiniteElementError::upstream(error, self))
77 }
78}