conspire/domain/fem/block/density/
mod.rs1#[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}