1use crate::{
2 constitutive::{ConstitutiveError, solid::elastic_hyperviscous::ElasticHyperviscous},
3 fem::block::element::{
4 Element, ElementNodalCoordinates, ElementNodalVelocities, FiniteElementError,
5 solid::viscoelastic::ViscoelasticFiniteElement, surface::SurfaceElement,
6 },
7 math::{Scalar, Tensor},
8};
9
10pub trait ElasticHyperviscousFiniteElement<
11 C,
12 const G: usize,
13 const M: usize,
14 const N: usize,
15 const P: usize,
16> where
17 C: ElasticHyperviscous,
18 Self: ViscoelasticFiniteElement<C, G, M, N, P>,
19{
20 fn viscous_dissipation(
21 &self,
22 constitutive_model: &C,
23 nodal_coordinates: &ElementNodalCoordinates<N>,
24 nodal_velocities: &ElementNodalVelocities<N>,
25 ) -> Result<Scalar, FiniteElementError>;
26 fn dissipation_potential(
27 &self,
28 constitutive_model: &C,
29 nodal_coordinates: &ElementNodalCoordinates<N>,
30 nodal_velocities: &ElementNodalVelocities<N>,
31 ) -> Result<Scalar, FiniteElementError>;
32}
33
34impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
35 ElasticHyperviscousFiniteElement<C, G, 3, N, P> for Element<G, N, O>
36where
37 C: ElasticHyperviscous,
38 Self: ViscoelasticFiniteElement<C, G, 3, N, P>,
39{
40 fn viscous_dissipation(
41 &self,
42 constitutive_model: &C,
43 nodal_coordinates: &ElementNodalCoordinates<N>,
44 nodal_velocities: &ElementNodalVelocities<N>,
45 ) -> Result<Scalar, FiniteElementError> {
46 viscous_dissipation::<_, _, _, _, _, O, _>(
47 self,
48 constitutive_model,
49 nodal_coordinates,
50 nodal_velocities,
51 )
52 }
53 fn dissipation_potential(
54 &self,
55 constitutive_model: &C,
56 nodal_coordinates: &ElementNodalCoordinates<N>,
57 nodal_velocities: &ElementNodalVelocities<N>,
58 ) -> Result<Scalar, FiniteElementError> {
59 dissipation_potential::<_, _, _, _, _, O, _>(
60 self,
61 constitutive_model,
62 nodal_coordinates,
63 nodal_velocities,
64 )
65 }
66}
67
68impl<C, const G: usize, const N: usize, const O: usize, const P: usize>
69 ElasticHyperviscousFiniteElement<C, G, 2, N, P> for SurfaceElement<G, N, O>
70where
71 C: ElasticHyperviscous,
72 Self: ViscoelasticFiniteElement<C, G, 2, N, P>,
73{
74 fn viscous_dissipation(
75 &self,
76 constitutive_model: &C,
77 nodal_coordinates: &ElementNodalCoordinates<N>,
78 nodal_velocities: &ElementNodalVelocities<N>,
79 ) -> Result<Scalar, FiniteElementError> {
80 viscous_dissipation::<_, _, _, _, _, O, _>(
81 self,
82 constitutive_model,
83 nodal_coordinates,
84 nodal_velocities,
85 )
86 }
87 fn dissipation_potential(
88 &self,
89 constitutive_model: &C,
90 nodal_coordinates: &ElementNodalCoordinates<N>,
91 nodal_velocities: &ElementNodalVelocities<N>,
92 ) -> Result<Scalar, FiniteElementError> {
93 dissipation_potential::<_, _, _, _, _, O, _>(
94 self,
95 constitutive_model,
96 nodal_coordinates,
97 nodal_velocities,
98 )
99 }
100}
101
102fn viscous_dissipation<
103 C,
104 F,
105 const G: usize,
106 const M: usize,
107 const N: usize,
108 const O: usize,
109 const P: usize,
110>(
111 element: &F,
112 constitutive_model: &C,
113 nodal_coordinates: &ElementNodalCoordinates<N>,
114 nodal_velocities: &ElementNodalVelocities<N>,
115) -> Result<Scalar, FiniteElementError>
116where
117 C: ElasticHyperviscous,
118 F: ViscoelasticFiniteElement<C, G, M, N, P>,
119{
120 match element
121 .deformation_gradients(nodal_coordinates)
122 .iter()
123 .zip(
124 element
125 .deformation_gradient_rates(nodal_coordinates, nodal_velocities)
126 .iter()
127 .zip(element.integration_weights()),
128 )
129 .map(
130 |(deformation_gradient, (deformation_gradient_rate, integration_weight))| {
131 Ok::<_, ConstitutiveError>(
132 constitutive_model
133 .viscous_dissipation(deformation_gradient, deformation_gradient_rate)?
134 * integration_weight,
135 )
136 },
137 )
138 .sum()
139 {
140 Ok(helmholtz_free_energy) => Ok(helmholtz_free_energy),
141 Err(error) => Err(FiniteElementError::Upstream(
142 format!("{error}"),
143 format!("{element:?}"),
144 )),
145 }
146}
147
148fn dissipation_potential<
149 C,
150 F,
151 const G: usize,
152 const M: usize,
153 const N: usize,
154 const O: usize,
155 const P: usize,
156>(
157 element: &F,
158 constitutive_model: &C,
159 nodal_coordinates: &ElementNodalCoordinates<N>,
160 nodal_velocities: &ElementNodalVelocities<N>,
161) -> Result<Scalar, FiniteElementError>
162where
163 C: ElasticHyperviscous,
164 F: ViscoelasticFiniteElement<C, G, M, N, P>,
165{
166 match element
167 .deformation_gradients(nodal_coordinates)
168 .iter()
169 .zip(
170 element
171 .deformation_gradient_rates(nodal_coordinates, nodal_velocities)
172 .iter()
173 .zip(element.integration_weights()),
174 )
175 .map(
176 |(deformation_gradient, (deformation_gradient_rate, integration_weight))| {
177 Ok::<_, ConstitutiveError>(
178 constitutive_model
179 .dissipation_potential(deformation_gradient, deformation_gradient_rate)?
180 * integration_weight,
181 )
182 },
183 )
184 .sum()
185 {
186 Ok(helmholtz_free_energy) => Ok(helmholtz_free_energy),
187 Err(error) => Err(FiniteElementError::Upstream(
188 format!("{error}"),
189 format!("{element:?}"),
190 )),
191 }
192}