Skip to main content

conspire/domain/fem/block/density/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    fem::{
6        NodalReferenceCoordinates,
7        block::{
8            Block,
9            element::{ElementNodalReferenceCoordinates, FiniteElement},
10        },
11    },
12    geometry::mesh::PrimitiveConnectivity,
13    math::{Quantity, Tensor, TensorList, TensorListVec},
14    units::{Density, Mass},
15};
16
17pub use crate::domain::density::{DensityField, NoDensity};
18
19pub trait Densities<const G: usize> {
20    fn at(&self, element: usize) -> TensorList<Quantity<Density>, G>;
21}
22
23pub type ElementDensities<const G: usize> = TensorListVec<Quantity<Density>, G>;
24
25impl<const G: usize> Densities<G> for ElementDensities<G> {
26    fn at(&self, element: usize) -> TensorList<Quantity<Density>, G> {
27        self[element].clone()
28    }
29}
30
31impl<const G: usize> Densities<G> for Quantity<Density> {
32    fn at(&self, _element: usize) -> TensorList<Quantity<Density>, G> {
33        [*self; G].into()
34    }
35}
36
37impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize, R>
38    Block<C, F, G, M, N, P, R>
39{
40    pub fn with_density<S>(self, density: S) -> Block<C, F, G, M, N, P, S> {
41        Block {
42            constitutive_model: self.constitutive_model,
43            connectivity: self.connectivity,
44            elements: self.elements,
45            density,
46        }
47    }
48    pub fn density(&self) -> &R {
49        &self.density
50    }
51}
52
53impl<C, F, R, const G: usize, const N: usize> Block<C, F, G, 3, N, N, R>
54where
55    F: FiniteElement<G, 3, N, N>,
56    R: Densities<G>,
57{
58    pub fn mass(&self) -> Quantity<Mass> {
59        self.elements()
60            .iter()
61            .enumerate()
62            .flat_map(|(element_index, element)| {
63                self.density()
64                    .at(element_index)
65                    .into_iter()
66                    .zip(element.integration_weights())
67                    .map(|(density, integration_weight)| density * integration_weight)
68            })
69            .sum()
70    }
71}
72
73impl<C, F, D, const G: usize, const N: usize>
74    From<(
75        C,
76        D,
77        PrimitiveConnectivity<3, N>,
78        &NodalReferenceCoordinates<3>,
79    )> for Block<C, F, G, 3, N, N, <D as DensityField>::Resolved<ElementDensities<G>>>
80where
81    F: FiniteElement<G, 3, N, N> + From<ElementNodalReferenceCoordinates<N>>,
82    D: DensityField,
83{
84    fn from(
85        (constitutive_model, density_field, connectivity, coordinates): (
86            C,
87            D,
88            PrimitiveConnectivity<3, N>,
89            &NodalReferenceCoordinates<3>,
90        ),
91    ) -> Self {
92        let shape_functions = F::shape_functions_at_integration_points();
93        let density = density_field.resolve(|field| {
94            connectivity
95                .iter()
96                .map(|nodes| {
97                    let element_coordinates = Self::element_coordinates(coordinates, nodes);
98                    shape_functions
99                        .iter()
100                        .map(|shape_functions| {
101                            field.density(
102                                &element_coordinates
103                                    .iter()
104                                    .zip(shape_functions.iter())
105                                    .map(|(coordinate, shape_function)| coordinate * shape_function)
106                                    .sum(),
107                            )
108                        })
109                        .collect()
110                })
111                .collect::<ElementDensities<G>>()
112        });
113        Block::from((constitutive_model, connectivity, coordinates)).with_density(density)
114    }
115}
116
117impl<C, F, D, const G: usize, const N: usize>
118    From<(C, D, Vec<[usize; N]>, &NodalReferenceCoordinates<3>)>
119    for Block<C, F, G, 3, N, N, <D as DensityField>::Resolved<ElementDensities<G>>>
120where
121    F: FiniteElement<G, 3, N, N> + From<ElementNodalReferenceCoordinates<N>>,
122    D: DensityField,
123{
124    fn from(
125        (constitutive_model, density_field, connectivity, coordinates): (
126            C,
127            D,
128            Vec<[usize; N]>,
129            &NodalReferenceCoordinates<3>,
130        ),
131    ) -> Self {
132        Self::from((
133            constitutive_model,
134            density_field,
135            PrimitiveConnectivity::from(connectivity),
136            coordinates,
137        ))
138    }
139}