conspire/fem/block/element/linear/tetrahedron/
mod.rs

1#[cfg(test)]
2mod test;
3
4use super::*;
5use crate::{
6    constitutive::{Constitutive, Parameters},
7    math::{tensor_rank_0_list, tensor_rank_1, tensor_rank_1_list, tensor_rank_1_list_2d},
8    mechanics::Scalar,
9};
10use std::array::from_fn;
11
12const G: usize = 1;
13const M: usize = 3;
14const N: usize = 4;
15const P: usize = G;
16
17#[cfg(test)]
18const Q: usize = N;
19
20pub type Tetrahedron<C> = Element<C, G, N>;
21
22impl<C, Y> FiniteElement<C, G, N, Y> for Tetrahedron<C>
23where
24    C: Constitutive<Y>,
25    Y: Parameters,
26{
27    fn new(
28        constitutive_model_parameters: Y,
29        reference_nodal_coordinates: ReferenceNodalCoordinates<N>,
30    ) -> Self {
31        let (gradient_vectors, integration_weights) = Self::initialize(reference_nodal_coordinates);
32        Self {
33            constitutive_models: from_fn(|_| <C>::new(constitutive_model_parameters)),
34            gradient_vectors,
35            integration_weights,
36        }
37    }
38    fn reference() -> ReferenceNodalCoordinates<N> {
39        tensor_rank_1_list([
40            tensor_rank_1([0.0, 0.0, 0.0]),
41            tensor_rank_1([1.0, 0.0, 0.0]),
42            tensor_rank_1([0.0, 1.0, 0.0]),
43            tensor_rank_1([0.0, 0.0, 1.0]),
44        ])
45    }
46    fn reset(&mut self) {
47        let (gradient_vectors, integration_weights) = Self::initialize(Self::reference());
48        self.gradient_vectors = gradient_vectors;
49        self.integration_weights = integration_weights;
50    }
51}
52
53impl<C> Tetrahedron<C> {
54    fn initialize(
55        reference_nodal_coordinates: ReferenceNodalCoordinates<N>,
56    ) -> (GradientVectors<G, N>, Scalars<G>) {
57        let standard_gradient_operator = &Self::standard_gradient_operators()[0];
58        let (operator, jacobian) = (reference_nodal_coordinates * standard_gradient_operator)
59            .inverse_transpose_and_determinant();
60        let gradient_vectors = tensor_rank_1_list_2d([operator * standard_gradient_operator]);
61        let integration_weights = tensor_rank_0_list([jacobian * Self::integration_weight()]);
62        (gradient_vectors, integration_weights)
63    }
64    const fn integration_weight() -> Scalar {
65        1.0 / 6.0
66    }
67    #[cfg(test)]
68    const fn shape_functions_at_integration_points() -> ShapeFunctionsAtIntegrationPoints<G, Q> {
69        tensor_rank_1_list([tensor_rank_1([0.25; Q])])
70    }
71    const fn standard_gradient_operators() -> StandardGradientOperators<M, N, P> {
72        tensor_rank_1_list_2d([tensor_rank_1_list([
73            tensor_rank_1([-1.0, -1.0, -1.0]),
74            tensor_rank_1([1.0, 0.0, 0.0]),
75            tensor_rank_1([0.0, 1.0, 0.0]),
76            tensor_rank_1([0.0, 0.0, 1.0]),
77        ])])
78    }
79}