Skip to main content

conspire/domain/fem/block/element/solid/hyperelastic/internal_variables/
mod.rs

1use 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}