conspire/domain/vem/block/element/
mod.rs1use crate::math::Reference;
2pub mod solid;
3#[cfg(test)]
4mod test;
5
6use crate::{
7 domain::block::element::{ElementError, ElementKind},
8 fem::block::element::{
9 ElementNodalReferenceCoordinates as FemElementNodalReferenceCoordinates, FiniteElement,
10 linear::Tetrahedron,
11 },
12 math::{
13 CrossProduct, Current, Quantity, Scalar, Tensor, TensorArray, TensorRank1, TensorRank1List,
14 TensorRank1Vec, TensorRank1Vec2D, TensorVector,
15 },
16 mechanics::ReferenceCoordinate,
17 units::{Area, Length, ReciprocalLength, Velocity, Volume},
18 vem::{NodalCoordinates, NodalReferenceCoordinates, NodalVelocities},
19};
20
21use std::fmt::{self, Debug, Display, Formatter};
22
23pub type ElementNodalCoordinates = NodalCoordinates;
24pub type ElementNodalVelocities = NodalVelocities;
25pub type ElementNodalReferenceCoordinates = TensorRank1Vec2D<3, Reference, Length>;
26pub type GradientVectors = TensorRank1Vec2D<3, Reference, ReciprocalLength>;
27pub type IntegrationWeights = TensorVector<Quantity<Volume>>;
28
29pub type TetrahedraQuantities<U> = Vec<TensorRank1List<3, Current, 4, U>>;
30pub type TetrahedraCoordinates = TetrahedraQuantities<Length>;
31pub type TetrahedraVelocities = TetrahedraQuantities<Velocity>;
32
33pub struct Element {
34 faces_nodes: Vec<Vec<usize>>,
35 gradient_vectors: GradientVectors,
36 integration_weights: IntegrationWeights,
37 stabilization: Scalar,
38 tetrahedra: Vec<Tetrahedron>,
39 tetrahedra_nodes: Vec<[usize; 3]>,
40}
41
42impl Element {
43 pub(crate) fn upstream(&self, error: impl Display) -> VirtualElementError {
44 VirtualElementError::upstream(error, self)
45 }
46}
47
48pub trait VirtualElement
49where
50 for<'a> Self: From<(
51 ElementNodalReferenceCoordinates,
52 &'a [usize],
53 &'a [usize],
54 &'a [Vec<usize>],
55 )>,
56{
57 fn element_center<U>(
58 nodal_quantities: &TensorRank1Vec<3, Current, U>,
59 ) -> TensorRank1<3, Current, U>;
60 fn faces_centers<U>(
61 &self,
62 nodal_quantities: &TensorRank1Vec<3, Current, U>,
63 ) -> TensorRank1Vec<3, Current, U>;
64 fn faces_nodes(&self) -> &[Vec<usize>];
65 fn gradient_vectors(&self) -> &GradientVectors;
66 fn integration_weights(&self) -> &IntegrationWeights;
67 fn stabilization(&self) -> Scalar;
68 fn tetrahedra(&self) -> &[Tetrahedron];
69 fn tetrahedra_coordinates<U>(
70 &self,
71 nodal_quantities: &TensorRank1Vec<3, Current, U>,
72 ) -> TetrahedraQuantities<U>;
73 fn tetrahedra_nodes(&self) -> &[[usize; 3]];
74}
75
76impl VirtualElement for Element {
77 fn element_center<U>(
78 nodal_quantities: &TensorRank1Vec<3, Current, U>,
79 ) -> TensorRank1<3, Current, U> {
80 nodal_quantities
81 .iter()
82 .cloned()
83 .sum::<TensorRank1<3, Current, U>>()
84 / nodal_quantities.len() as Scalar
85 }
86 fn faces_centers<U>(
87 &self,
88 nodal_quantities: &TensorRank1Vec<3, Current, U>,
89 ) -> TensorRank1Vec<3, Current, U> {
90 self.faces_nodes()
91 .iter()
92 .map(|face_nodes| {
93 face_nodes
94 .iter()
95 .map(|&face_node| nodal_quantities[face_node].clone())
96 .sum::<TensorRank1<3, Current, U>>()
97 / (face_nodes.len() as Scalar)
98 })
99 .collect()
100 }
101 fn faces_nodes(&self) -> &[Vec<usize>] {
102 &self.faces_nodes
103 }
104 fn gradient_vectors(&self) -> &GradientVectors {
105 &self.gradient_vectors
106 }
107 fn integration_weights(&self) -> &IntegrationWeights {
108 &self.integration_weights
109 }
110 fn stabilization(&self) -> Scalar {
111 self.stabilization
112 }
113 fn tetrahedra(&self) -> &[Tetrahedron] {
114 &self.tetrahedra
115 }
116 fn tetrahedra_coordinates<U>(
117 &self,
118 nodal_quantities: &TensorRank1Vec<3, Current, U>,
119 ) -> TetrahedraQuantities<U> {
120 let element_center = Self::element_center(nodal_quantities);
121 let faces_centers = self.faces_centers(nodal_quantities);
122 self.tetrahedra_nodes()
123 .iter()
124 .map(|&[face, node_b, node_a]| {
125 [
126 faces_centers[face].clone(),
127 nodal_quantities[node_b].clone(),
128 nodal_quantities[node_a].clone(),
129 element_center.clone(),
130 ]
131 .into()
132 })
133 .collect()
134 }
135 fn tetrahedra_nodes(&self) -> &[[usize; 3]] {
136 &self.tetrahedra_nodes
137 }
138}
139
140impl
141 From<(
142 ElementNodalReferenceCoordinates,
143 &[usize],
144 &[usize],
145 &[Vec<usize>],
146 )> for Element
147{
148 fn from(
149 (reference_nodal_coordinates, element_faces, element_nodes, block_faces_nodes): (
150 ElementNodalReferenceCoordinates,
151 &[usize],
152 &[usize],
153 &[Vec<usize>],
154 ),
155 ) -> Self {
156 let faces_nodes = element_faces
157 .iter()
158 .map(|&element_face| {
159 block_faces_nodes[element_face]
160 .iter()
161 .map(|face_node| {
162 element_nodes
163 .iter()
164 .position(|element_node| face_node == element_node)
165 .unwrap()
166 })
167 .collect::<Vec<_>>()
168 })
169 .collect::<Vec<_>>();
170 let mut nodal_coordinates =
171 NodalReferenceCoordinates::from(vec![
172 ReferenceCoordinate::from([0.0, 0.0, 0.0]);
173 element_nodes.len()
174 ]);
175 faces_nodes
176 .iter()
177 .zip(reference_nodal_coordinates.iter())
178 .for_each(|(face_nodes, face_coordinates)| {
179 face_nodes
180 .iter()
181 .zip(face_coordinates.iter())
182 .for_each(|(&node, coordinates)| nodal_coordinates[node] = coordinates.clone())
183 });
184 let element_center = nodal_coordinates.into_iter().sum::<ReferenceCoordinate>()
185 / (element_nodes.len() as Scalar);
186 let mut area_vectors = vec![TensorRank1::<3, Reference, Area>::zero(); element_nodes.len()];
187 let tetrahedra_nodes = faces_nodes
188 .iter()
189 .enumerate()
190 .flat_map(|(face, face_nodes)| {
191 (0..face_nodes.len())
192 .map(|spot| {
193 [
194 face,
195 face_nodes[(spot + 1) % face_nodes.len()],
196 face_nodes[spot],
197 ]
198 })
199 .collect::<Vec<_>>()
200 })
201 .collect::<Vec<_>>();
202 let tetrahedra = faces_nodes
203 .iter()
204 .zip(reference_nodal_coordinates.iter())
205 .flat_map(|(face_nodes, face_coordinates)| {
206 let num_nodes_face = face_coordinates.len();
207 let face_center = face_coordinates
208 .iter()
209 .cloned()
210 .sum::<ReferenceCoordinate>()
211 / (num_nodes_face as Scalar);
212 let mut face_area_vector = TensorRank1::<3, Reference, Area>::zero();
213 let face_tetrahedra = (0..num_nodes_face)
214 .map(|spot| {
215 let next = (spot + 1) % num_nodes_face;
216 let e_1 = &face_coordinates[next] - &face_coordinates[spot];
217 let e_2 = &face_center - &face_coordinates[next];
218 let cross = e_1.cross(&e_2);
219 face_area_vector += ✗
220 area_vectors[face_nodes[spot]] += ✗
221 area_vectors[face_nodes[next]] += ✗
222 Tetrahedron::from(FemElementNodalReferenceCoordinates::from([
223 face_center.clone(),
224 face_coordinates[next].clone(),
225 face_coordinates[spot].clone(),
226 element_center.clone(),
227 ]))
228 })
229 .collect::<Vec<_>>();
230 let shared = &face_area_vector / (num_nodes_face as Scalar);
231 face_nodes
232 .iter()
233 .for_each(|&node| area_vectors[node] += &shared);
234 face_tetrahedra
235 })
236 .collect::<Vec<_>>();
237 let element_volume = tetrahedra
238 .iter()
239 .map(|tetrahedron| tetrahedron.volume())
240 .sum::<Quantity<Volume>>();
241 let gradient_vectors = GradientVectors::from(vec![
242 area_vectors
243 .into_iter()
244 .map(|area_vector| area_vector / (element_volume * 6.0))
245 .collect::<TensorRank1Vec<3, Reference, ReciprocalLength>>(),
246 ]);
247 let integration_weights = IntegrationWeights::from([element_volume]);
248 Self {
249 faces_nodes,
250 gradient_vectors,
251 integration_weights,
252 stabilization: 0.1,
253 tetrahedra,
254 tetrahedra_nodes,
255 }
256 }
257}
258
259impl Debug for Element {
260 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
261 write!(f, "VirtualElement {{ ... }}",)
262 }
263}
264
265pub struct VirtualElementKind;
266
267impl ElementKind for VirtualElementKind {
268 const NAME: &'static str = "virtual element";
269}
270
271pub type VirtualElementError = ElementError<VirtualElementKind>;