1#[cfg(test)]
2mod test;
3
4use crate::{
5 fem::block::element::{
6 ElementNodalEitherCoordinates, ElementNodalReferenceCoordinates, FiniteElement,
7 GradientVectors, ParametricCoordinate, ParametricCoordinates, ParametricReference,
8 ShapeFunctions, ShapeFunctionsAtIntegrationPoints, ShapeFunctionsGradients,
9 StandardGradientOperators, StandardGradientOperatorsTransposed,
10 composite::{
11 CompositeElement, NormalizedProjectionMatrix, ParametricGradientOperators,
12 ProjectionMatrix, ShapeFunctionIntegrals, ShapeFunctionIntegralsProducts,
13 },
14 linear::Tetrahedron as LinearTetrahedron,
15 quadratic::Tetrahedron as QuadraticTetrahedron,
16 },
17 math::{Scalar, ScalarList, Tensor, TensorRank1},
18};
19
20const G: usize = 4;
21const M: usize = 3;
22const N: usize = 10;
23const P: usize = 4;
24const Q: usize = 12;
25
26pub type Tetrahedron = CompositeElement<G, N>;
27
28impl From<ElementNodalReferenceCoordinates<N>> for Tetrahedron {
29 fn from(reference_nodal_coordinates: ElementNodalReferenceCoordinates<N>) -> Self {
30 let gradient_vectors = Self::projected_gradient_vectors(&reference_nodal_coordinates);
31 let integration_weights =
32 Self::reference_jacobians(&reference_nodal_coordinates) * Self::integration_weight();
33 Self {
34 gradient_vectors,
35 integration_weights,
36 }
37 }
38}
39
40impl FiniteElement<G, M, N, P> for Tetrahedron {
41 fn integration_points() -> ParametricCoordinates<G, M> {
42 QuadraticTetrahedron::integration_points() }
44 fn integration_weights(&self) -> &ScalarList<G> {
45 &self.integration_weights
46 }
47 fn parametric_reference() -> ParametricReference<M, N> {
48 [
49 [0.0, 0.0, 0.0],
50 [1.0, 0.0, 0.0],
51 [0.0, 1.0, 0.0],
52 [0.0, 0.0, 1.0],
53 [0.5, 0.0, 0.0],
54 [0.5, 0.5, 0.0],
55 [0.0, 0.5, 0.0],
56 [0.0, 0.0, 0.5],
57 [0.5, 0.0, 0.5],
58 [0.0, 0.5, 0.5],
59 ]
60 .into()
61 }
62 fn parametric_weights() -> ScalarList<G> {
63 [1.0 / 24.0; G].into()
64 }
65 fn scaled_jacobians<const I: usize>(
66 nodal_coordinates: ElementNodalEitherCoordinates<I, N>,
67 ) -> ScalarList<P> {
68 LinearTetrahedron::scaled_jacobians(Self::corner_coordinates(nodal_coordinates))
69 }
70 fn shape_functions(parametric_coordinate: ParametricCoordinate<M>) -> ShapeFunctions<P> {
71 LinearTetrahedron::shape_functions(parametric_coordinate) }
73 fn shape_functions_gradients(
74 parametric_coordinate: ParametricCoordinate<M>,
75 ) -> ShapeFunctionsGradients<M, P> {
76 LinearTetrahedron::shape_functions_gradients(parametric_coordinate) }
78}
79
80impl Tetrahedron {
81 fn corner_coordinates<const I: usize>(
82 nodal_coordinates: ElementNodalEitherCoordinates<I, N>,
83 ) -> ElementNodalEitherCoordinates<I, P> {
84 nodal_coordinates.into_iter().take(P).collect()
85 }
86 const fn integration_weight() -> Scalar {
87 1.0 / 24.0
88 }
89 fn inverse_normalized_projection_matrix() -> NormalizedProjectionMatrix<P> {
90 const DIAG: Scalar = 4.0 / 640.0;
91 const OFF: Scalar = -1.0 / 640.0;
92 [
93 [DIAG, OFF, OFF, OFF],
94 [OFF, DIAG, OFF, OFF],
95 [OFF, OFF, DIAG, OFF],
96 [OFF, OFF, OFF, DIAG],
97 ]
98 .into()
99 }
100 fn inverse_projection_matrix(
101 reference_jacobians_subelements: &ScalarList<Q>,
102 ) -> NormalizedProjectionMatrix<P> {
103 Self::shape_function_integrals_products()
104 .iter()
105 .zip(reference_jacobians_subelements)
106 .map(
107 |(shape_function_integrals_products, reference_jacobian_subelement)| {
108 shape_function_integrals_products * reference_jacobian_subelement
109 },
110 )
111 .sum::<ProjectionMatrix<P>>()
112 .inverse()
113 }
114 fn projected_gradient_vectors(
115 reference_nodal_coordinates: &ElementNodalReferenceCoordinates<N>,
116 ) -> GradientVectors<G, N> {
117 let parametric_gradient_operators = Self::shape_functions_gradients_at_integration_points()
118 .iter()
119 .map(|standard_gradient_operator| {
120 reference_nodal_coordinates * standard_gradient_operator
121 })
122 .collect::<ParametricGradientOperators<Q>>();
123 let reference_jacobians_subelements =
124 Self::reference_jacobians_subelements(reference_nodal_coordinates);
125 let inverse_projection_matrix =
126 Self::inverse_projection_matrix(&reference_jacobians_subelements);
127 Self::shape_functions_at_integration_points()
128 .iter()
129 .map(|shape_functions_at_integration_point| {
130 Self::standard_gradient_operators_transposed()
131 .iter()
132 .map(|standard_gradient_operators_a| {
133 Self::shape_function_integrals()
134 .iter()
135 .zip(
136 standard_gradient_operators_a.iter().zip(
137 parametric_gradient_operators
138 .iter()
139 .zip(reference_jacobians_subelements.iter()),
140 ),
141 )
142 .map(
143 |(
144 shape_function_integral,
145 (
146 standard_gradient_operator,
147 (
148 parametric_gradient_operator,
149 reference_jacobian_subelement,
150 ),
151 ),
152 )| {
153 (parametric_gradient_operator.inverse_transpose()
154 * standard_gradient_operator)
155 * reference_jacobian_subelement
156 * (shape_functions_at_integration_point
157 * (&inverse_projection_matrix
158 * shape_function_integral))
159 },
160 )
161 .sum()
162 })
163 .collect()
164 })
165 .collect()
166 }
167 fn reference_jacobians(
168 reference_nodal_coordinates: &ElementNodalReferenceCoordinates<N>,
169 ) -> ScalarList<G> {
170 let vector = Self::inverse_normalized_projection_matrix()
171 * Self::shape_function_integrals()
172 .iter()
173 .zip(Self::reference_jacobians_subelements(
174 reference_nodal_coordinates,
175 ))
176 .map(|(shape_function_integral, reference_jacobian_subelement)| {
177 shape_function_integral * reference_jacobian_subelement
178 })
179 .sum::<TensorRank1<P, 9>>();
180 Self::shape_functions_at_integration_points()
181 .iter()
182 .map(|shape_functions_at_integration_point| {
183 shape_functions_at_integration_point * &vector
184 })
185 .collect()
186 }
187 fn reference_jacobians_subelements(
188 reference_nodal_coordinates: &ElementNodalReferenceCoordinates<N>,
189 ) -> ScalarList<Q> {
190 Self::shape_functions_gradients_at_integration_points()
191 .iter()
192 .map(|standard_gradient_operator| {
193 reference_nodal_coordinates * standard_gradient_operator
194 })
195 .collect::<ParametricGradientOperators<Q>>()
196 .iter()
197 .map(|parametric_gradient_operator| parametric_gradient_operator.determinant())
198 .collect()
199 }
200 fn shape_functions_at_integration_points() -> ShapeFunctionsAtIntegrationPoints<G, P> {
201 const DIAG: Scalar = 0.585_410_196_624_968_5;
202 const OFF: Scalar = 0.138_196_601_125_010_5;
203 [
204 [DIAG, OFF, OFF, OFF],
205 [OFF, DIAG, OFF, OFF],
206 [OFF, OFF, DIAG, OFF],
207 [OFF, OFF, OFF, DIAG],
208 ]
209 .into()
210 }
211 fn shape_function_integrals() -> ShapeFunctionIntegrals<Q, P> {
212 [
213 [200.0, 40.0, 40.0, 40.0],
214 [40.0, 200.0, 40.0, 40.0],
215 [40.0, 40.0, 200.0, 40.0],
216 [40.0, 40.0, 40.0, 200.0],
217 [30.0, 70.0, 30.0, 30.0],
218 [10.0, 50.0, 50.0, 50.0],
219 [30.0, 30.0, 30.0, 70.0],
220 [50.0, 50.0, 10.0, 50.0],
221 [50.0, 50.0, 50.0, 10.0],
222 [30.0, 30.0, 70.0, 30.0],
223 [50.0, 10.0, 50.0, 50.0],
224 [70.0, 30.0, 30.0, 30.0],
225 ]
226 .into()
227 }
228 fn shape_function_integrals_products() -> ShapeFunctionIntegralsProducts<Q, P> {
229 [
230 [
231 [128.0, 24.0, 24.0, 24.0],
232 [24.0, 8.0, 4.0, 4.0],
233 [24.0, 4.0, 8.0, 4.0],
234 [24.0, 4.0, 4.0, 8.0],
235 ],
236 [
237 [8.0, 24.0, 4.0, 4.0],
238 [24.0, 128.0, 24.0, 24.0],
239 [4.0, 24.0, 8.0, 4.0],
240 [4.0, 24.0, 4.0, 8.0],
241 ],
242 [
243 [8.0, 4.0, 24.0, 4.0],
244 [4.0, 8.0, 24.0, 4.0],
245 [24.0, 24.0, 128.0, 24.0],
246 [4.0, 4.0, 24.0, 8.0],
247 ],
248 [
249 [8.0, 4.0, 4.0, 24.0],
250 [4.0, 8.0, 4.0, 24.0],
251 [4.0, 4.0, 8.0, 24.0],
252 [24.0, 24.0, 24.0, 128.0],
253 ],
254 [
255 [7.0, 13.0, 5.0, 5.0],
256 [13.0, 31.0, 13.0, 13.0],
257 [5.0, 13.0, 7.0, 5.0],
258 [5.0, 13.0, 5.0, 7.0],
259 ],
260 [
261 [1.0, 3.0, 3.0, 3.0],
262 [3.0, 17.0, 15.0, 15.0],
263 [3.0, 15.0, 17.0, 15.0],
264 [3.0, 15.0, 15.0, 17.0],
265 ],
266 [
267 [7.0, 5.0, 5.0, 13.0],
268 [5.0, 7.0, 5.0, 13.0],
269 [5.0, 5.0, 7.0, 13.0],
270 [13.0, 13.0, 13.0, 31.0],
271 ],
272 [
273 [17.0, 15.0, 3.0, 15.0],
274 [15.0, 17.0, 3.0, 15.0],
275 [3.0, 3.0, 1.0, 3.0],
276 [15.0, 15.0, 3.0, 17.0],
277 ],
278 [
279 [17.0, 15.0, 15.0, 3.0],
280 [15.0, 17.0, 15.0, 3.0],
281 [15.0, 15.0, 17.0, 3.0],
282 [3.0, 3.0, 3.0, 1.0],
283 ],
284 [
285 [7.0, 5.0, 13.0, 5.0],
286 [5.0, 7.0, 13.0, 5.0],
287 [13.0, 13.0, 31.0, 13.0],
288 [5.0, 5.0, 13.0, 7.0],
289 ],
290 [
291 [17.0, 3.0, 15.0, 15.0],
292 [3.0, 1.0, 3.0, 3.0],
293 [15.0, 3.0, 17.0, 15.0],
294 [15.0, 3.0, 15.0, 17.0],
295 ],
296 [
297 [31.0, 13.0, 13.0, 13.0],
298 [13.0, 7.0, 5.0, 5.0],
299 [13.0, 5.0, 7.0, 5.0],
300 [13.0, 5.0, 5.0, 7.0],
301 ],
302 ]
303 .into()
304 }
305 fn shape_functions_gradients_at_integration_points() -> StandardGradientOperators<M, N, Q> {
306 [
307 [
308 [-2.0, -2.0, -2.0],
309 [0.0, 0.0, 0.0],
310 [0.0, 0.0, 0.0],
311 [0.0, 0.0, 0.0],
312 [2.0, 0.0, 0.0],
313 [0.0, 0.0, 0.0],
314 [0.0, 2.0, 0.0],
315 [0.0, 0.0, 2.0],
316 [0.0, 0.0, 0.0],
317 [0.0, 0.0, 0.0],
318 ],
319 [
320 [0.0, 0.0, 0.0],
321 [2.0, 0.0, 0.0],
322 [0.0, 0.0, 0.0],
323 [0.0, 0.0, 0.0],
324 [-2.0, -2.0, -2.0],
325 [0.0, 2.0, 0.0],
326 [0.0, 0.0, 0.0],
327 [0.0, 0.0, 0.0],
328 [0.0, 0.0, 2.0],
329 [0.0, 0.0, 0.0],
330 ],
331 [
332 [0.0, 0.0, 0.0],
333 [0.0, 0.0, 0.0],
334 [0.0, 2.0, 0.0],
335 [0.0, 0.0, 0.0],
336 [0.0, 0.0, 0.0],
337 [2.0, 0.0, 0.0],
338 [-2.0, -2.0, -2.0],
339 [0.0, 0.0, 0.0],
340 [0.0, 0.0, 0.0],
341 [0.0, 0.0, 2.0],
342 ],
343 [
344 [0.0, 0.0, 0.0],
345 [0.0, 0.0, 0.0],
346 [0.0, 0.0, 0.0],
347 [0.0, 0.0, 2.0],
348 [0.0, 0.0, 0.0],
349 [0.0, 0.0, 0.0],
350 [0.0, 0.0, 0.0],
351 [-2.0, -2.0, -2.0],
352 [2.0, 0.0, 0.0],
353 [0.0, 2.0, 0.0],
354 ],
355 [
356 [0.0, 0.0, 0.0],
357 [0.0, 0.0, 0.0],
358 [0.0, 0.0, 0.0],
359 [0.0, 0.0, 0.0],
360 [-2.0 / 3.0, -2.0, -2.0],
361 [4.0 / 3.0, 2.0, 0.0],
362 [-2.0 / 3.0, 0.0, 0.0],
363 [-2.0 / 3.0, 0.0, 0.0],
364 [4.0 / 3.0, 0.0, 2.0],
365 [-2.0 / 3.0, 0.0, 0.0],
366 ],
367 [
368 [0.0, 0.0, 0.0],
369 [0.0, 0.0, 0.0],
370 [0.0, 0.0, 0.0],
371 [0.0, 0.0, 0.0],
372 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
373 [4.0 / 3.0, 4.0 / 3.0, -2.0 / 3.0],
374 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
375 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
376 [4.0 / 3.0, -2.0 / 3.0, 4.0 / 3.0],
377 [-2.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0],
378 ],
379 [
380 [0.0, 0.0, 0.0],
381 [0.0, 0.0, 0.0],
382 [0.0, 0.0, 0.0],
383 [0.0, 0.0, 0.0],
384 [0.0, 0.0, -2.0 / 3.0],
385 [0.0, 0.0, -2.0 / 3.0],
386 [0.0, 0.0, -2.0 / 3.0],
387 [-2.0, -2.0, -2.0 / 3.0],
388 [2.0, 0.0, 4.0 / 3.0],
389 [0.0, 2.0, 4.0 / 3.0],
390 ],
391 [
392 [0.0, 0.0, 0.0],
393 [0.0, 0.0, 0.0],
394 [0.0, 0.0, 0.0],
395 [0.0, 0.0, 0.0],
396 [0.0, -4.0 / 3.0, -2.0],
397 [0.0, 2.0 / 3.0, 0.0],
398 [0.0, 2.0 / 3.0, 0.0],
399 [-2.0, -4.0 / 3.0, 0.0],
400 [2.0, 2.0 / 3.0, 2.0],
401 [0.0, 2.0 / 3.0, 0.0],
402 ],
403 [
404 [0.0, 0.0, 0.0],
405 [0.0, 0.0, 0.0],
406 [0.0, 0.0, 0.0],
407 [0.0, 0.0, 0.0],
408 [0.0, -2.0, -4.0 / 3.0],
409 [2.0, 2.0, 2.0 / 3.0],
410 [-2.0, 0.0, -4.0 / 3.0],
411 [0.0, 0.0, 2.0 / 3.0],
412 [0.0, 0.0, 2.0 / 3.0],
413 [0.0, 0.0, 2.0 / 3.0],
414 ],
415 [
416 [0.0, 0.0, 0.0],
417 [0.0, 0.0, 0.0],
418 [0.0, 0.0, 0.0],
419 [0.0, 0.0, 0.0],
420 [0.0, -2.0 / 3.0, 0.0],
421 [2.0, 4.0 / 3.0, 0.0],
422 [-2.0, -2.0 / 3.0, -2.0],
423 [0.0, -2.0 / 3.0, 0.0],
424 [0.0, -2.0 / 3.0, 0.0],
425 [0.0, 4.0 / 3.0, 2.0],
426 ],
427 [
428 [0.0, 0.0, 0.0],
429 [0.0, 0.0, 0.0],
430 [0.0, 0.0, 0.0],
431 [0.0, 0.0, 0.0],
432 [2.0 / 3.0, 0.0, 0.0],
433 [2.0 / 3.0, 0.0, 0.0],
434 [-4.0 / 3.0, 0.0, -2.0],
435 [-4.0 / 3.0, -2.0, 0.0],
436 [2.0 / 3.0, 0.0, 0.0],
437 [2.0 / 3.0, 2.0, 2.0],
438 ],
439 [
440 [0.0, 0.0, 0.0],
441 [0.0, 0.0, 0.0],
442 [0.0, 0.0, 0.0],
443 [0.0, 0.0, 0.0],
444 [2.0 / 3.0, -4.0 / 3.0, -4.0 / 3.0],
445 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
446 [-4.0 / 3.0, 2.0 / 3.0, -4.0 / 3.0],
447 [-4.0 / 3.0, -4.0 / 3.0, 2.0 / 3.0],
448 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
449 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
450 ],
451 ]
452 .into()
453 }
454 fn standard_gradient_operators_transposed() -> StandardGradientOperatorsTransposed<M, N, Q> {
455 [
456 [
457 [-2.0, -2.0, -2.0],
458 [0.0, 0.0, 0.0],
459 [0.0, 0.0, 0.0],
460 [0.0, 0.0, 0.0],
461 [0.0, 0.0, 0.0],
462 [0.0, 0.0, 0.0],
463 [0.0, 0.0, 0.0],
464 [0.0, 0.0, 0.0],
465 [0.0, 0.0, 0.0],
466 [0.0, 0.0, 0.0],
467 [0.0, 0.0, 0.0],
468 [0.0, 0.0, 0.0],
469 ],
470 [
471 [0.0, 0.0, 0.0],
472 [2.0, 0.0, 0.0],
473 [0.0, 0.0, 0.0],
474 [0.0, 0.0, 0.0],
475 [0.0, 0.0, 0.0],
476 [0.0, 0.0, 0.0],
477 [0.0, 0.0, 0.0],
478 [0.0, 0.0, 0.0],
479 [0.0, 0.0, 0.0],
480 [0.0, 0.0, 0.0],
481 [0.0, 0.0, 0.0],
482 [0.0, 0.0, 0.0],
483 ],
484 [
485 [0.0, 0.0, 0.0],
486 [0.0, 0.0, 0.0],
487 [0.0, 2.0, 0.0],
488 [0.0, 0.0, 0.0],
489 [0.0, 0.0, 0.0],
490 [0.0, 0.0, 0.0],
491 [0.0, 0.0, 0.0],
492 [0.0, 0.0, 0.0],
493 [0.0, 0.0, 0.0],
494 [0.0, 0.0, 0.0],
495 [0.0, 0.0, 0.0],
496 [0.0, 0.0, 0.0],
497 ],
498 [
499 [0.0, 0.0, 0.0],
500 [0.0, 0.0, 0.0],
501 [0.0, 0.0, 0.0],
502 [0.0, 0.0, 2.0],
503 [0.0, 0.0, 0.0],
504 [0.0, 0.0, 0.0],
505 [0.0, 0.0, 0.0],
506 [0.0, 0.0, 0.0],
507 [0.0, 0.0, 0.0],
508 [0.0, 0.0, 0.0],
509 [0.0, 0.0, 0.0],
510 [0.0, 0.0, 0.0],
511 ],
512 [
513 [2.0, 0.0, 0.0],
514 [-2.0, -2.0, -2.0],
515 [0.0, 0.0, 0.0],
516 [0.0, 0.0, 0.0],
517 [-2.0 / 3.0, -2.0, -2.0],
518 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
519 [0.0, 0.0, -2.0 / 3.0],
520 [0.0, -4.0 / 3.0, -2.0],
521 [0.0, -2.0, -4.0 / 3.0],
522 [0.0, -2.0 / 3.0, 0.0],
523 [2.0 / 3.0, 0.0, 0.0],
524 [2.0 / 3.0, -4.0 / 3.0, -4.0 / 3.0],
525 ],
526 [
527 [0.0, 0.0, 0.0],
528 [0.0, 2.0, 0.0],
529 [2.0, 0.0, 0.0],
530 [0.0, 0.0, 0.0],
531 [4.0 / 3.0, 2.0, 0.0],
532 [4.0 / 3.0, 4.0 / 3.0, -2.0 / 3.0],
533 [0.0, 0.0, -2.0 / 3.0],
534 [0.0, 2.0 / 3.0, 0.0],
535 [2.0, 2.0, 2.0 / 3.0],
536 [2.0, 4.0 / 3.0, 0.0],
537 [2.0 / 3.0, 0.0, 0.0],
538 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
539 ],
540 [
541 [0.0, 2.0, 0.0],
542 [0.0, 0.0, 0.0],
543 [-2.0, -2.0, -2.0],
544 [0.0, 0.0, 0.0],
545 [-2.0 / 3.0, 0.0, 0.0],
546 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
547 [0.0, 0.0, -2.0 / 3.0],
548 [0.0, 2.0 / 3.0, 0.0],
549 [-2.0, 0.0, -4.0 / 3.0],
550 [-2.0, -2.0 / 3.0, -2.0],
551 [-4.0 / 3.0, 0.0, -2.0],
552 [-4.0 / 3.0, 2.0 / 3.0, -4.0 / 3.0],
553 ],
554 [
555 [0.0, 0.0, 2.0],
556 [0.0, 0.0, 0.0],
557 [0.0, 0.0, 0.0],
558 [-2.0, -2.0, -2.0],
559 [-2.0 / 3.0, 0.0, 0.0],
560 [-2.0 / 3.0, -2.0 / 3.0, -2.0 / 3.0],
561 [-2.0, -2.0, -2.0 / 3.0],
562 [-2.0, -4.0 / 3.0, 0.0],
563 [0.0, 0.0, 2.0 / 3.0],
564 [0.0, -2.0 / 3.0, 0.0],
565 [-4.0 / 3.0, -2.0, 0.0],
566 [-4.0 / 3.0, -4.0 / 3.0, 2.0 / 3.0],
567 ],
568 [
569 [0.0, 0.0, 0.0],
570 [0.0, 0.0, 2.0],
571 [0.0, 0.0, 0.0],
572 [2.0, 0.0, 0.0],
573 [4.0 / 3.0, 0.0, 2.0],
574 [4.0 / 3.0, -2.0 / 3.0, 4.0 / 3.0],
575 [2.0, 0.0, 4.0 / 3.0],
576 [2.0, 2.0 / 3.0, 2.0],
577 [0.0, 0.0, 2.0 / 3.0],
578 [0.0, -2.0 / 3.0, 0.0],
579 [2.0 / 3.0, 0.0, 0.0],
580 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
581 ],
582 [
583 [0.0, 0.0, 0.0],
584 [0.0, 0.0, 0.0],
585 [0.0, 0.0, 2.0],
586 [0.0, 2.0, 0.0],
587 [-2.0 / 3.0, 0.0, 0.0],
588 [-2.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0],
589 [0.0, 2.0, 4.0 / 3.0],
590 [0.0, 2.0 / 3.0, 0.0],
591 [0.0, 0.0, 2.0 / 3.0],
592 [0.0, 4.0 / 3.0, 2.0],
593 [2.0 / 3.0, 2.0, 2.0],
594 [2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0],
595 ],
596 ]
597 .into()
598 }
599}