conspire/domain/fem/block/element/surface/linear/quadrilateral/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 fem::block::element::{
6 ElementNodalEitherCoordinates, FRAC_1_SQRT_3, FiniteElement, ParametricCoordinate,
7 ParametricCoordinates, ParametricReference, ShapeFunctions, ShapeFunctionsGradients,
8 surface::{M, linear::LinearSurfaceElement},
9 },
10 math::{ScalarList, Tensor, TensorArray},
11 mechanics::Coordinate,
12};
13
14const G: usize = 4;
15const N: usize = 4;
16const P: usize = N;
17
18const CORNERS: [[usize; 2]; N] = [[1, 3], [2, 0], [3, 1], [0, 2]];
19
20pub type Quadrilateral = LinearSurfaceElement<G, N>;
21
22impl FiniteElement<G, M, N, P> for Quadrilateral {
23 fn integration_points() -> ParametricCoordinates<G, M> {
24 [
25 [-FRAC_1_SQRT_3, -FRAC_1_SQRT_3],
26 [FRAC_1_SQRT_3, -FRAC_1_SQRT_3],
27 [FRAC_1_SQRT_3, FRAC_1_SQRT_3],
28 [-FRAC_1_SQRT_3, FRAC_1_SQRT_3],
29 ]
30 .into()
31 }
32 fn integration_weights(&self) -> &ScalarList<G> {
33 &self.integration_weights
34 }
35 fn parametric_reference() -> ParametricReference<M, N> {
36 [[-1.0, -1.0], [1.0, -1.0], [1.0, 1.0], [-1.0, 1.0]].into()
37 }
38 fn parametric_weights() -> ScalarList<G> {
39 [1.0; G].into()
40 }
41 fn scaled_jacobians<const I: usize>(
42 nodal_coordinates: ElementNodalEitherCoordinates<I, N>,
43 ) -> ScalarList<P> {
44 let mut u = Coordinate::zero();
45 let mut v = Coordinate::zero();
46 let mut n = Coordinate::zero();
47 let x = (&nodal_coordinates[1] - &nodal_coordinates[0])
48 + (&nodal_coordinates[2] - &nodal_coordinates[3]);
49 let y = (&nodal_coordinates[2] - &nodal_coordinates[1])
50 + (&nodal_coordinates[3] - &nodal_coordinates[0]);
51 let nc = x.cross(&y).normalized();
52 CORNERS
53 .into_iter()
54 .enumerate()
55 .map(|(node, [node_a, node_b])| {
56 u = &nodal_coordinates[node_a] - &nodal_coordinates[node];
57 v = &nodal_coordinates[node_b] - &nodal_coordinates[node];
58 n = u.cross(&v);
59 (&n * &nc) / u.norm() / v.norm()
60 })
61 .collect()
62 }
63 fn shape_functions(parametric_coordinate: ParametricCoordinate<M>) -> ShapeFunctions<N> {
64 let [xi_1, xi_2] = parametric_coordinate.into();
65 [
66 (1.0 - xi_1) * (1.0 - xi_2) / 4.0,
67 (1.0 + xi_1) * (1.0 - xi_2) / 4.0,
68 (1.0 + xi_1) * (1.0 + xi_2) / 4.0,
69 (1.0 - xi_1) * (1.0 + xi_2) / 4.0,
70 ]
71 .into()
72 }
73 fn shape_functions_gradients(
74 parametric_coordinate: ParametricCoordinate<M>,
75 ) -> ShapeFunctionsGradients<M, N> {
76 let [xi_1, xi_2] = parametric_coordinate.into();
77 [
78 [-(1.0 - xi_2) / 4.0, -(1.0 - xi_1) / 4.0],
79 [(1.0 - xi_2) / 4.0, -(1.0 + xi_1) / 4.0],
80 [(1.0 + xi_2) / 4.0, (1.0 + xi_1) / 4.0],
81 [-(1.0 + xi_2) / 4.0, (1.0 - xi_1) / 4.0],
82 ]
83 .into()
84 }
85}