deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
reference_cell.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2020 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
17
26
29#include <deal.II/grid/tria.h>
30
31#include <algorithm>
32#include <iostream>
33#include <memory>
34
36
37namespace
38{
39 namespace VTKCellType
40 {
41 // Define VTK constants for linear, quadratic and
42 // high-order Lagrange geometrices
43 enum : unsigned int
44 {
45 VTK_VERTEX = 1,
46 // Linear cells
47 VTK_LINE = 3,
48 VTK_TRIANGLE = 5,
49 VTK_QUAD = 9,
50 VTK_TETRA = 10,
51 VTK_HEXAHEDRON = 12,
52 VTK_WEDGE = 13,
53 VTK_PYRAMID = 14,
54 // Quadratic cells
55 VTK_QUADRATIC_EDGE = 21,
56 VTK_QUADRATIC_TRIANGLE = 22,
57 VTK_QUADRATIC_QUAD = 23,
58 VTK_QUADRATIC_TETRA = 24,
59 VTK_QUADRATIC_HEXAHEDRON = 25,
60 VTK_QUADRATIC_WEDGE = 26,
61 VTK_QUADRATIC_PYRAMID = 27,
62 // Lagrange cells
63 VTK_LAGRANGE_CURVE = 68,
64 VTK_LAGRANGE_TRIANGLE = 69,
65 VTK_LAGRANGE_QUADRILATERAL = 70,
66 VTK_LAGRANGE_TETRAHEDRON = 71,
67 VTK_LAGRANGE_HEXAHEDRON = 72,
68 VTK_LAGRANGE_WEDGE = 73,
69 VTK_LAGRANGE_PYRAMID = 74,
70 // Invalid code
72 };
73
74 } // namespace VTKCellType
75
76} // namespace
77
78
79
80template <int dim>
81std::string
83{
84 switch (this->kind)
85 {
87 return "Vertex";
89 return "Line";
91 return "Tri";
93 return "Quad";
95 return "Tet";
97 return "Pyramid";
99 return "Wedge";
101 return "Hex";
103 return "Invalid";
104 default:
106 }
107
108 return "Invalid";
109}
110
111
112
113namespace
114{
115 // Return vertex_no-th vertex of the child_no-ith child cell.
116 //
117 // @note This function is not yet implemented in 3d since it is only called on
118 // faces of cells.
119 template <int dim>
121 child_vertex(const ReferenceCell<dim> reference_cell,
122 const unsigned int child_no,
123 const unsigned int vertex_no,
124 const RefinementCase<dim> refinement_case)
125 {
126 if (dim > 1)
127 AssertIndexRange(child_no, reference_cell.n_children(refinement_case));
128 AssertIndexRange(vertex_no, reference_cell.n_vertices());
129
130 constexpr Point<dim> V0;
131 // V isn't used for dim == 0
132 [[maybe_unused]] const auto V = [](const unsigned int d) {
133 return Point<dim>::unit_vector(d);
134 };
135
136 switch (reference_cell)
137 {
139 return V0;
141 {
144 if constexpr (dim == 1)
145 {
146 static constexpr ndarray<Point<1>, 2, 2>
147 isotropic_child_vertices = {{
148 {{V0, 0.5 * V(0)}},
149 {{0.5 * V(0), V(0)}},
150 }};
151 return isotropic_child_vertices[child_no][vertex_no];
152 }
153 else
155 }
157 {
160 if constexpr (dim == 2)
161 {
162 static constexpr ndarray<Point<2>, 4, 3>
163 isotropic_child_vertices = {{
164 {{V0, 0.5 * V(0), 0.5 * V(1)}},
165 {{0.5 * V(0), V(0), 0.5 * (V(0) + V(1))}},
166 {{0.5 * V(1), 0.5 * V(0) + 0.5 * V(1), V(1)}},
167 {{0.5 * V(0), 0.5 * V(0) + 0.5 * V(1), 0.5 * V(1)}},
168 }};
169 return isotropic_child_vertices[child_no][vertex_no];
170 }
171 else
173 }
175 {
176 if constexpr (dim == 2)
177 {
178 static constexpr Point<2> M = 0.5 * (V(0) + V(1));
179
180 static constexpr ndarray<Point<2>, 2, 4> cut_x_child_vertices =
181 {{
182 {{V0, 0.5 * V(0), V(1), V(1) + 0.5 * V(0)}},
183 {{0.5 * V(0), V(0), 0.5 * V(0) + V(1), V(0) + V(1)}},
184 }};
185
186 static constexpr ndarray<Point<2>, 2, 4> cut_y_child_vertices =
187 {{
188 {{V0, V(0), 0.5 * V(1), V(0) + 0.5 * V(1)}},
189 {{0.5 * V(1), V(0) + 0.5 * V(1), V(1), V(0) + V(1)}},
190 }};
191
192 static constexpr ndarray<Point<2>, 4, 4>
193 isotropic_child_vertices = {{
194 {{V0, 0.5 * V(0), 0.5 * V(1), M}},
195 {{0.5 * V(0), V(0), M, V(0) + 0.5 * V(1)}},
196 {{0.5 * V(1), M, V(1), V(1) + 0.5 * V(0)}},
197 {{M, V(0) + 0.5 * V(1), V(1) + 0.5 * V(0), V(0) + V(1)}},
198 }};
199
200 switch (refinement_case)
201 {
203 return cut_x_child_vertices[child_no][vertex_no];
205 return cut_y_child_vertices[child_no][vertex_no];
207 return isotropic_child_vertices[child_no][vertex_no];
208 default:
210 }
211 }
212 else
214 }
220 return {};
221 default:
223 return {};
224 }
225 }
226} // namespace
227
228
229
230template <int dim>
233 const unsigned int face_no,
234 const unsigned int subface_no,
235 const unsigned int subface_vertex_no,
236 const RefinementCase<dim - 1> face_refinement_case) const
237{
239 if (dim > 1)
240 {
241 AssertIndexRange(subface_no,
243 face_refinement_case));
244 Assert(face_refinement_case != RefinementCase<dim - 1>::no_refinement,
245 ExcMessage("This function may only be called for subfaces."));
246 }
247 AssertIndexRange(subface_vertex_no,
248 face_reference_cell(face_no).n_vertices());
250 Point<dim> p;
251 for (const unsigned int vertex_no :
253 p += face_vertex_location(face_no, vertex_no) *
254 face_reference_cell(face_no).d_linear_shape_function(
255 child_vertex(face_reference_cell(face_no),
256 subface_no,
257 subface_vertex_no,
258 face_refinement_case),
259 vertex_no);
260
261 return p;
262}
263
264
265
266template <int dim>
267std::pair<unsigned int, RefinementCase<dim - 1>>
269 const types::geometric_orientation combined_face_orientation,
270 const internal::SubfaceCase<dim> subface_case,
271 const unsigned int subface_no) const
272{
273 // 1. in 1d subfaces don't exist, but we still support some subface code
274 // (such as QProjector's functions) to enable dimension-independent
275 // programming. To match the convention used by 3d this will always return
276 // (0, isotropic_refinement).
277 //
278 // 2. historically we have permitted subface calculations in 2d for unrefined
279 // faces. In that case we don't actually need the value of subface_case
280 // since there is only one possible refinement - the returned value has to
281 // be isotropic_refinement.
282 //
283 // 3. Similarly, in 3d we treat case_none as case_isotropic.
284 if constexpr (dim == 1)
285 {
286 (void)subface_case;
287 AssertIndexRange(combined_face_orientation, n_face_orientations(0));
288 AssertIndexRange(subface_no, 1);
289 return std::make_pair(0, RefinementCase<dim - 1>::isotropic_refinement);
290 }
291
292 if constexpr (dim == 2)
293 {
294 (void)subface_case;
295 AssertIndexRange(combined_face_orientation, n_face_orientations(0));
296 AssertIndexRange(subface_no,
297 face_reference_cell(0).n_isotropic_children());
298 return std::make_pair(combined_face_orientation ==
300 1 - subface_no :
301 subface_no,
303 }
304 else if constexpr (dim == 3)
305 {
307
308 static const RefinementCase<dim - 1>
309 equivalent_refine_case[internal::SubfaceCase<dim>::case_isotropic + 1]
311 // case_none. there should be only
312 // invalid values here. However, as
313 // this function is also called (in
314 // tests) for cells which have no
315 // refined faces, use isotropic
316 // refinement instead
317 {RefinementCase<dim - 1>::cut_xy,
318 RefinementCase<dim - 1>::cut_xy,
319 RefinementCase<dim - 1>::cut_xy,
320 RefinementCase<dim - 1>::cut_xy},
321 // case_x
322 {RefinementCase<dim - 1>::cut_x,
323 RefinementCase<dim - 1>::cut_x,
324 RefinementCase<dim - 1>::no_refinement,
325 RefinementCase<dim - 1>::no_refinement},
326 // case_x1y
327 {RefinementCase<dim - 1>::cut_xy,
328 RefinementCase<dim - 1>::cut_xy,
329 RefinementCase<dim - 1>::cut_x,
330 RefinementCase<dim - 1>::no_refinement},
331 // case_x2y
332 {RefinementCase<dim - 1>::cut_x,
333 RefinementCase<dim - 1>::cut_xy,
334 RefinementCase<dim - 1>::cut_xy,
335 RefinementCase<dim - 1>::no_refinement},
336 // case_x1y2y
337 {RefinementCase<dim - 1>::cut_xy,
338 RefinementCase<dim - 1>::cut_xy,
339 RefinementCase<dim - 1>::cut_xy,
340 RefinementCase<dim - 1>::cut_xy},
341 // case_y
342 {RefinementCase<dim - 1>::cut_y,
343 RefinementCase<dim - 1>::cut_y,
344 RefinementCase<dim - 1>::no_refinement,
345 RefinementCase<dim - 1>::no_refinement},
346 // case_y1x
347 {RefinementCase<dim - 1>::cut_xy,
348 RefinementCase<dim - 1>::cut_xy,
349 RefinementCase<dim - 1>::cut_y,
350 RefinementCase<dim - 1>::no_refinement},
351 // case_y2x
352 {RefinementCase<dim - 1>::cut_y,
353 RefinementCase<dim - 1>::cut_xy,
354 RefinementCase<dim - 1>::cut_xy,
355 RefinementCase<dim - 1>::no_refinement},
356 // case_y1x2x
357 {RefinementCase<dim - 1>::cut_xy,
358 RefinementCase<dim - 1>::cut_xy,
359 RefinementCase<dim - 1>::cut_xy,
360 RefinementCase<dim - 1>::cut_xy},
361 // case_xy (case_isotropic)
362 {RefinementCase<dim - 1>::cut_xy,
363 RefinementCase<dim - 1>::cut_xy,
364 RefinementCase<dim - 1>::cut_xy,
365 RefinementCase<dim - 1>::cut_xy}};
366
367 constexpr unsigned int X = numbers::invalid_unsigned_int;
368 static const unsigned int
369 equivalent_subface_number[internal::SubfaceCase<dim>::case_isotropic +
371 // case_none, see above
372 {0, 1, 2, 3},
373 // case_x
374 {0, 1, X, X},
375 // case_x1y
376 {0, 2, 1, X},
377 // case_x2y
378 {0, 1, 3, X},
379 // case_x1y2y
380 {0, 2, 1, 3},
381 // case_y
382 {0, 1, X, X},
383 // case_y1x
384 {0, 1, 1, X},
385 // case_y2x
386 {0, 2, 3, X},
387 // case_y1x2x
388 {0, 1, 2, 3},
389 // case_xy (case_isotropic)
390 {0, 1, 2, 3}};
391
392 static const RefinementCase<dim - 1> rotated_refinement_case[4] = {
393 RefinementCase<dim - 1>::no_refinement,
394 RefinementCase<dim - 1>::cut_y,
395 RefinementCase<dim - 1>::cut_x,
396 RefinementCase<dim - 1>::cut_xy};
397 const auto [face_orientation, face_rotation, face_flip] =
398 internal::split_face_orientation(combined_face_orientation);
399
400 const auto equivalent_refinement_case =
401 equivalent_refine_case[subface_case][subface_no];
402 const unsigned int equivalent_subface_no =
403 equivalent_subface_number[subface_case][subface_no];
404 // make sure, that we got a valid subface and RefineCase
405 Assert(equivalent_refinement_case != RefinementCase<dim>::no_refinement,
407 Assert(equivalent_subface_no != X, ExcInternalError());
408 // now, finally respect non-standard faces
409 const RefinementCase<dim - 1> final_refinement_case =
410 (face_orientation == face_rotation ?
411 rotated_refinement_case[equivalent_refinement_case] :
413
414 const unsigned int final_subface_no =
416 final_refinement_case),
417 /*face_no = */ 4,
418 equivalent_subface_no,
419 face_orientation,
420 face_flip,
421 face_rotation,
423
424 return std::make_pair(final_subface_no, final_refinement_case);
425 }
426 else
427 {
428 (void)combined_face_orientation;
429 (void)subface_case;
430 (void)subface_no;
431
433 return {};
434 }
435}
436
437
438
439template <int dim>
440template <int spacedim>
441std::unique_ptr<Mapping<dim, spacedim>>
442ReferenceCell<dim>::get_default_mapping(const unsigned int degree) const
443{
444 if (is_hyper_cube())
445 return std::make_unique<MappingQ<dim, spacedim>>(degree);
446 else if (is_simplex())
447 if (degree == 1)
448 return std::make_unique<MappingP1<dim, spacedim>>();
449 else
450 return std::make_unique<MappingFE<dim, spacedim>>(
452 else if (*this == ReferenceCells::Pyramid)
453 return std::make_unique<MappingFE<dim, spacedim>>(
455 else if (*this == ReferenceCells::Wedge)
456 return std::make_unique<MappingFE<dim, spacedim>>(
458 else
459 {
461 }
462
463 return std::make_unique<MappingQ<dim, spacedim>>(degree);
464}
465
466
467
468template <int dim>
469template <int spacedim>
472{
473 if (is_hyper_cube())
474 {
476 }
477 else if (is_simplex())
478 {
480 return mapping;
481 }
482 else if (*this == ReferenceCells::Pyramid)
483 {
486 return mapping;
487 }
488 else if (*this == ReferenceCells::Wedge)
489 {
492 return mapping;
493 }
494 else
495 {
497 }
498
499 return StaticMappingQ1<dim, spacedim>::mapping; // never reached
500}
501
502
503
504template <int dim>
506ReferenceCell<dim>::get_gauss_type_quadrature(const unsigned n_points_1d) const
507{
508 if (is_hyper_cube())
509 return QGauss<dim>(n_points_1d);
510 else if (is_simplex())
511 return QGaussSimplex<dim>(n_points_1d);
512 else if (*this == ReferenceCells::Pyramid)
513 return QGaussPyramid<dim>(n_points_1d);
514 else if (*this == ReferenceCells::Wedge)
515 return QGaussWedge<dim>(n_points_1d);
516 else
518
519 return Quadrature<dim>(); // never reached
520}
521
522
523
524template <int dim>
525const Quadrature<dim> &
527{
528 // A function that is used to fill a quadrature object of the
529 // desired type the first time we encounter a particular
530 // reference cell
531 const auto create_quadrature = [](const ReferenceCell<dim> &reference_cell) {
532 std::vector<Point<dim>> vertices(reference_cell.n_vertices());
533 for (const unsigned int v : reference_cell.vertex_indices())
534 vertices[v] = reference_cell.vertex(v);
535
536 return Quadrature<dim>(vertices);
537 };
538
539 if (is_hyper_cube())
540 {
541 static const Quadrature<dim> quadrature = create_quadrature(*this);
542 return quadrature;
543 }
544 else if (is_simplex())
545 {
546 static const Quadrature<dim> quadrature = create_quadrature(*this);
547 return quadrature;
548 }
549 else if (*this == ReferenceCells::Pyramid)
550 {
551 static const Quadrature<dim> quadrature = create_quadrature(*this);
552 return quadrature;
553 }
554 else if (*this == ReferenceCells::Wedge)
555 {
556 static const Quadrature<dim> quadrature = create_quadrature(*this);
557 return quadrature;
558 }
559 else
561
562 static const Quadrature<dim> dummy;
563 return dummy; // never reached
564}
565
566
567
568template <int dim>
569unsigned int
571 const unsigned int vertex_n) const
572{
573 AssertIndexRange(vertex_n, n_vertices());
574
575 switch (this->kind)
576 {
579 return vertex_n;
581 {
582 constexpr std::array<unsigned int, 4> exodus_to_deal{{0, 1, 3, 2}};
583 return exodus_to_deal[vertex_n];
584 }
586 return vertex_n;
588 {
589 constexpr std::array<unsigned int, 8> exodus_to_deal{
590 {0, 1, 3, 2, 4, 5, 7, 6}};
591 return exodus_to_deal[vertex_n];
592 }
594 {
595 constexpr std::array<unsigned int, 6> exodus_to_deal{
596 {2, 1, 0, 5, 4, 3}};
597 return exodus_to_deal[vertex_n];
598 }
600 {
601 constexpr std::array<unsigned int, 5> exodus_to_deal{{0, 1, 3, 2, 4}};
602 return exodus_to_deal[vertex_n];
603 }
604 default:
606 }
607
609}
610
611
612
613template <int dim>
614unsigned int
616{
617 AssertIndexRange(face_n, n_faces());
618
619 switch (this->kind)
620 {
622 return 0;
625 return face_n;
627 {
628 constexpr std::array<unsigned int, 4> exodus_to_deal{{2, 1, 3, 0}};
629 return exodus_to_deal[face_n];
630 }
632 {
633 constexpr std::array<unsigned int, 4> exodus_to_deal{{1, 3, 2, 0}};
634 return exodus_to_deal[face_n];
635 }
637 {
638 constexpr std::array<unsigned int, 6> exodus_to_deal{
639 {2, 1, 3, 0, 4, 5}};
640 return exodus_to_deal[face_n];
641 }
643 {
644 constexpr std::array<unsigned int, 6> exodus_to_deal{{3, 4, 2, 0, 1}};
645 return exodus_to_deal[face_n];
646 }
648 {
649 constexpr std::array<unsigned int, 5> exodus_to_deal{{3, 2, 4, 1, 0}};
650 return exodus_to_deal[face_n];
651 }
652 default:
654 }
655
657}
658
659
660
661template <int dim>
662unsigned int
663ReferenceCell<dim>::unv_vertex_to_deal_vertex(const unsigned int vertex_n) const
664{
665 AssertIndexRange(vertex_n, n_vertices());
666 // Information on this file format isn't easy to find - the documents here
667 //
668 // https://www.ceas3.uc.edu/sdrluff/
669 //
670 // Don't actually explain anything about the sections we care about (2412) in
671 // any detail. For node numbering I worked backwards from what is actually in
672 // our test files (since that's supposed to work), which all use some
673 // non-standard clockwise numbering scheme which starts at the bottom right
674 // vertex.
675 if (*this == ReferenceCells::Line)
676 {
677 return vertex_n;
678 }
680 {
681 constexpr std::array<unsigned int, 4> unv_to_deal{{1, 0, 2, 3}};
682 return unv_to_deal[vertex_n];
683 }
684 else if (*this == ReferenceCells::Hexahedron)
685 {
686 constexpr std::array<unsigned int, 8> unv_to_deal{
687 {6, 7, 5, 4, 2, 3, 1, 0}};
688 return unv_to_deal[vertex_n];
689 }
690
692
694}
695
696
697
698template <int dim>
699unsigned int
701{
702 switch (this->kind)
703 {
705 return VTKCellType::VTK_VERTEX;
707 return VTKCellType::VTK_LINE;
709 return VTKCellType::VTK_TRIANGLE;
711 return VTKCellType::VTK_QUAD;
713 return VTKCellType::VTK_TETRA;
715 return VTKCellType::VTK_PYRAMID;
717 return VTKCellType::VTK_WEDGE;
719 return VTKCellType::VTK_HEXAHEDRON;
721 return VTKCellType::VTK_INVALID;
722 default:
724 }
725
726 return VTKCellType::VTK_INVALID;
727}
728
729
730
731template <int dim>
732unsigned int
734{
735 switch (this->kind)
736 {
738 return VTKCellType::VTK_VERTEX;
740 return VTKCellType::VTK_QUADRATIC_EDGE;
742 return VTKCellType::VTK_QUADRATIC_TRIANGLE;
744 return VTKCellType::VTK_QUADRATIC_QUAD;
746 return VTKCellType::VTK_QUADRATIC_TETRA;
748 return VTKCellType::VTK_QUADRATIC_PYRAMID;
750 return VTKCellType::VTK_QUADRATIC_WEDGE;
752 return VTKCellType::VTK_QUADRATIC_HEXAHEDRON;
754 return VTKCellType::VTK_INVALID;
755 default:
757 }
758
759 return VTKCellType::VTK_INVALID;
760}
761
762
763
764template <int dim>
765unsigned int
767{
768 switch (this->kind)
769 {
771 return VTKCellType::VTK_VERTEX;
773 return VTKCellType::VTK_LAGRANGE_CURVE;
775 return VTKCellType::VTK_LAGRANGE_TRIANGLE;
777 return VTKCellType::VTK_LAGRANGE_QUADRILATERAL;
779 return VTKCellType::VTK_LAGRANGE_TETRAHEDRON;
781 return VTKCellType::VTK_LAGRANGE_PYRAMID;
783 return VTKCellType::VTK_LAGRANGE_WEDGE;
785 return VTKCellType::VTK_LAGRANGE_HEXAHEDRON;
787 return VTKCellType::VTK_INVALID;
788 default:
790 }
791
792 return VTKCellType::VTK_INVALID;
793}
794
795
796
797template <int dim>
798unsigned int
800 const std::array<unsigned, dim> &node_indices,
801 const std::array<unsigned, dim> &nodes_per_direction,
802 const bool legacy_format) const
803{
804 (void)legacy_format;
805
806 if constexpr (dim == 0)
807 {
809 return 0;
810 }
811 else if constexpr (dim == 1)
812 {
817 const unsigned int i = node_indices[0];
818
819 const bool ibdy = (i == 0 || i == nodes_per_direction[0]);
820 // How many boundaries do we lie on at once?
821 const int nbdy = (ibdy ? 1 : 0);
822
823 if (nbdy == 1) // Vertex DOF
824 { // ijk is a corner node. Return the proper index (somewhere in [0,7]):
825 return i ? 1 : 0;
826 }
827
828 const int offset = 2;
829 return (i - 1) + offset;
830 }
831 else if constexpr (dim == 2)
832 {
838
839 const unsigned int i = node_indices[0];
840 const unsigned int j = node_indices[1];
841
842 const bool ibdy = (i == 0 || i == nodes_per_direction[0]);
843 const bool jbdy = (j == 0 || j == nodes_per_direction[1]);
844 // How many boundaries do we lie on at once?
845 const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0);
846
847 if (nbdy == 2) // Vertex DOF
848 { // ijk is a corner node. Return the proper index (somewhere in [0,3]):
849 return (i != 0u ? (j != 0u ? 2 : 1) : (j != 0u ? 3 : 0));
850 }
851
852 int offset = 4;
853 if (nbdy == 1) // Edge DOF
854 {
855 if (!ibdy)
856 { // On i axis
857 return (i - 1) +
858 (j != 0u ? nodes_per_direction[0] - 1 +
859 nodes_per_direction[1] - 1 :
860 0) +
861 offset;
862 }
863
864 if (!jbdy)
865 { // On j axis
866 return (j - 1) +
867 (i != 0u ? nodes_per_direction[0] - 1 :
868 2 * (nodes_per_direction[0] - 1) +
869 nodes_per_direction[1] - 1) +
870 offset;
871 }
872 }
873
874 offset += 2 * (nodes_per_direction[0] - 1 + nodes_per_direction[1] - 1);
875 // nbdy == 0: Face DOF
876 return offset + (i - 1) + (nodes_per_direction[0] - 1) * ((j - 1));
877 }
878 else if constexpr (dim == 3)
879 {
891
892 const unsigned int i = node_indices[0];
893 const unsigned int j = node_indices[1];
894 const unsigned int k = node_indices[2];
895
896 const bool ibdy = (i == 0 || i == nodes_per_direction[0]);
897 const bool jbdy = (j == 0 || j == nodes_per_direction[1]);
898 const bool kbdy = (k == 0 || k == nodes_per_direction[2]);
899 // How many boundaries do we lie on at once?
900 const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0) + (kbdy ? 1 : 0);
901
902 if (nbdy == 3) // Vertex DOF
903 { // ijk is a corner node. Return the proper index (somewhere in [0,7]):
904 return (i != 0u ? (j != 0u ? 2 : 1) : (j != 0u ? 3 : 0)) +
905 (k != 0u ? 4 : 0);
906 }
907
908 int offset = 8;
909 if (nbdy == 2) // Edge DOF
910 {
911 if (!ibdy)
912 { // On i axis
913 return (i - 1) +
914 (j != 0u ? nodes_per_direction[0] - 1 +
915 nodes_per_direction[1] - 1 :
916 0) +
917 (k != 0u ? 2 * (nodes_per_direction[0] - 1 +
918 nodes_per_direction[1] - 1) :
919 0) +
920 offset;
921 }
922 if (!jbdy)
923 { // On j axis
924 return (j - 1) +
925 (i != 0u ? nodes_per_direction[0] - 1 :
926 2 * (nodes_per_direction[0] - 1) +
927 nodes_per_direction[1] - 1) +
928 (k != 0u ? 2 * (nodes_per_direction[0] - 1 +
929 nodes_per_direction[1] - 1) :
930 0) +
931 offset;
932 }
933 // !kbdy, On k axis
934 offset +=
935 4 * (nodes_per_direction[0] - 1) + 4 * (nodes_per_direction[1] - 1);
936 if (legacy_format)
937 return (k - 1) +
938 (nodes_per_direction[2] - 1) *
939 (i != 0u ? (j != 0u ? 3 : 1) : (j != 0u ? 2 : 0)) +
940 offset;
941 else
942 return (k - 1) +
943 (nodes_per_direction[2] - 1) *
944 (i != 0u ? (j != 0u ? 2 : 1) : (j != 0u ? 3 : 0)) +
945 offset;
946 }
947
948 offset += 4 * (nodes_per_direction[0] - 1 + nodes_per_direction[1] - 1 +
949 nodes_per_direction[2] - 1);
950 if (nbdy == 1) // Face DOF
951 {
952 if (ibdy) // On i-normal face
953 {
954 return (j - 1) + ((nodes_per_direction[1] - 1) * (k - 1)) +
955 (i != 0u ? (nodes_per_direction[1] - 1) *
956 (nodes_per_direction[2] - 1) :
957 0) +
958 offset;
959 }
960 offset +=
961 2 * (nodes_per_direction[1] - 1) * (nodes_per_direction[2] - 1);
962 if (jbdy) // On j-normal face
963 {
964 return (i - 1) + ((nodes_per_direction[0] - 1) * (k - 1)) +
965 (j != 0u ? (nodes_per_direction[2] - 1) *
966 (nodes_per_direction[0] - 1) :
967 0) +
968 offset;
969 }
970 offset +=
971 2 * (nodes_per_direction[2] - 1) * (nodes_per_direction[0] - 1);
972 // kbdy, On k-normal face
973 return (i - 1) + ((nodes_per_direction[0] - 1) * (j - 1)) +
974 (k != 0u ? (nodes_per_direction[0] - 1) *
975 (nodes_per_direction[1] - 1) :
976 0) +
977 offset;
978 }
979
980 // nbdy == 0: Body DOF
981 offset +=
982 2 * ((nodes_per_direction[1] - 1) * (nodes_per_direction[2] - 1) +
983 (nodes_per_direction[2] - 1) * (nodes_per_direction[0] - 1) +
984 (nodes_per_direction[0] - 1) * (nodes_per_direction[1] - 1));
985 return offset + (i - 1) +
986 (nodes_per_direction[0] - 1) *
987 ((j - 1) + (nodes_per_direction[1] - 1) * ((k - 1)));
988 }
989 else
990 {
992 return 0;
993 }
994}
995
996
997template <int dim>
998unsigned int
1000 const unsigned int vertex_index) const
1001{
1002 AssertIndexRange(vertex_index, n_vertices());
1003
1004 // For some of the following, deal.II uses the same ordering as VTK
1005 // and in that case, we only need to return 'vertex_index' (i.e.,
1006 // use the identity mapping). For some others, we need to translate.
1007 //
1008 // For the ordering, see the VTK manual (for example at
1009 // http://www.princeton.edu/~efeibush/viscourse/vtk.pdf, page 9).
1010 switch (this->kind)
1011 {
1013 return vertex_index;
1015 return vertex_index;
1017 return vertex_index;
1019 {
1020 static constexpr std::array<unsigned int, 4> index_translation_table =
1021 {{0, 1, 3, 2}};
1022 return index_translation_table[vertex_index];
1023 }
1025 return vertex_index;
1027 {
1028 static constexpr std::array<unsigned int, 5> index_translation_table =
1029 {{0, 1, 3, 2, 4}};
1030 return index_translation_table[vertex_index];
1031 }
1033 return vertex_index;
1035 {
1036 static constexpr std::array<unsigned int, 8> index_translation_table =
1037 {{0, 1, 3, 2, 4, 5, 7, 6}};
1038 return index_translation_table[vertex_index];
1039 }
1041 {
1044 }
1045 default:
1047 }
1048
1050}
1051
1052
1053
1054template <int dim>
1055unsigned int
1057{
1058 /*
1059 From the GMSH documentation:
1060
1061 elm-type
1062 defines the geometrical type of the n-th element:
1063
1064 1
1065 Line (2 nodes).
1066
1067 2
1068 Triangle (3 nodes).
1069
1070 3
1071 Quadrangle (4 nodes).
1072
1073 4
1074 Tetrahedron (4 nodes).
1075
1076 5
1077 Hexahedron (8 nodes).
1078
1079 6
1080 Prism (6 nodes).
1081
1082 7
1083 Pyramid (5 nodes).
1084
1085 8
1086 Second order line (3 nodes: 2 associated with the vertices and 1 with the
1087 edge).
1088
1089 9
1090 Second order triangle (6 nodes: 3 associated with the vertices and 3 with
1091 the edges).
1093 10 Second order quadrangle (9 nodes: 4 associated with the
1094 vertices, 4 with the edges and 1 with the face).
1095
1096 11 Second order tetrahedron (10 nodes: 4 associated with the vertices and 6
1097 with the edges).
1099 12 Second order hexahedron (27 nodes: 8 associated with the vertices, 12
1100 with the edges, 6 with the faces and 1 with the volume).
1101
1102 13 Second order prism (18 nodes: 6 associated with the vertices, 9 with the
1103 edges and 3 with the quadrangular faces).
1105 14 Second order pyramid (14 nodes: 5 associated with the vertices, 8 with
1106 the edges and 1 with the quadrangular face).
1107
1108 15 Point (1 node).
1109 */
1110
1111 switch (this->kind)
1112 {
1114 return 15;
1116 return 1;
1118 return 2;
1120 return 3;
1122 return 4;
1124 return 7;
1126 return 6;
1128 return 5;
1130 default:
1132 }
1135}
1136
1137
1138
1139namespace
1140{
1141 // Compute the nearest point to @p on the line segment and the square of its
1142 // distance to @p.
1143 template <int dim>
1144 std::pair<Point<dim>, double>
1145 project_to_line(const Point<dim> &x0,
1146 const Point<dim> &x1,
1147 const Point<dim> &p)
1149 Assert(x0 != x1, ExcInternalError());
1150 // t is the convex combination coefficient (x = (1 - t) * x0 + t * x1)
1151 // defining the position of the closest point on the line (not line segment)
1152 // to p passing through x0 and x1. This formula is equivalent to the
1153 // standard 'project a vector onto another vector', where each vector is
1154 // shifted to start at x0.
1155 const double t = ((x1 - x0) * (p - x0)) / ((x1 - x0).norm_square());
1156
1157 // Only consider points between x0 and x1
1158 if (t <= 0)
1159 return std::make_pair(x0, x0.distance_square(p));
1160 else if (t <= 1)
1161 {
1162 const auto p2 = x0 + t * (x1 - x0);
1163 return std::make_pair(p2, p2.distance_square(p));
1165 else
1166 return std::make_pair(x1, x1.distance_square(p));
1167 }
1168
1169
1170
1171 // template base-case
1172 template <int dim>
1173 std::pair<Point<dim>, double>
1174 project_to_quad(const std::array<Point<dim>, 3> & /*vertices*/,
1175 const Point<dim> & /*p*/,
1176 const ReferenceCell<dim - 1> /*face_reference_cell*/)
1177 {
1179 return std::make_pair(Point<dim>(),
1180 std::numeric_limits<double>::signaling_NaN());
1181 }
1182
1200 template <>
1201 std::pair<Point<3>, double>
1202 project_to_quad(const std::array<Point<3>, 3> &vertices,
1203 const Point<3> &p,
1204 const ReferenceCell<2> face_reference_cell)
1205 {
1206 Assert(face_reference_cell == ReferenceCells::Triangle ||
1207 face_reference_cell == ReferenceCells::Quadrilateral,
1209
1210 // Make the problem slightly easier by shifting everything to avoid a point
1211 // at the origin (this way we can invert the matrix of vertices). Use 2.0 so
1212 // that the bottom left vertex of a Pyramid is now at x = 1.
1213 std::array<Point<3>, 3> shifted_vertices = vertices;
1214 const Tensor<1, 3> shift{{2.0, 2.0, 2.0}};
1215 for (Point<3> &shifted_vertex : shifted_vertices)
1216 shifted_vertex += shift;
1217 const Point<3> shifted_p = p + shift;
1218
1219 // As we are projecting onto a face of a reference cell, the vectors
1220 // describing its local coordinate system should be orthogonal. We don't
1221 // know which of the three vectors computed from p are mutually orthogonal
1222 // for triangles so that case requires an extra check.
1223 Tensor<1, 3> e0;
1224 Tensor<1, 3> e1;
1225 const Point<3> vertex = shifted_vertices[0];
1226 // Triangles are difficult because of two cases:
1227 // 1. the top face of a Tetrahedron, which does not have a right angle
1228 // 2. wedges and pyramids, whose faces do not lie on the reference simplex
1229 //
1230 // Deal with both by creating a locally orthogonal (but not necessarily
1231 // orthonormal) coordinate system and testing if the projected point is in
1232 // the triangle by expressing it as a convex combination of the vertices.
1233 if (face_reference_cell == ReferenceCells::Triangle)
1234 {
1235 e0 = shifted_vertices[1] - shifted_vertices[0];
1236 e1 = shifted_vertices[2] - shifted_vertices[0];
1237 e1 -= (e0 * e1) * e0 / (e0.norm_square());
1238 }
1239 else
1240 {
1241 e0 = shifted_vertices[1] - shifted_vertices[0];
1242 e1 = shifted_vertices[2] - shifted_vertices[0];
1243 }
1244 Assert(std::abs(e0 * e1) <= 1e-14, ExcInternalError());
1245 // the quadrilaterals on pyramids and wedges don't necessarily have edge
1246 // lengths of 1 so we cannot skip the denominator
1247 const double c0 = e0 * (shifted_p - vertex) / e0.norm_square();
1248 const double c1 = e1 * (shifted_p - vertex) / e1.norm_square();
1249 const Point<3> projected_shifted_p = vertex + c0 * e0 + c1 * e1;
1250
1251 bool in_quad = false;
1252 if (face_reference_cell == ReferenceCells::Triangle)
1253 {
1254 Tensor<2, 3> shifted_vertex_matrix;
1255 for (unsigned int i = 0; i < 3; ++i)
1256 shifted_vertex_matrix[i] = shifted_vertices[i];
1257 const Tensor<1, 3> combination_coordinates =
1258 invert(transpose(shifted_vertex_matrix)) * projected_shifted_p;
1259 bool is_convex_combination = true;
1260 for (unsigned int i = 0; i < 3; ++i)
1261 is_convex_combination = is_convex_combination &&
1262 (0.0 <= combination_coordinates[i]) &&
1263 (combination_coordinates[i] <= 1.0);
1264 in_quad = is_convex_combination;
1265 }
1266 else
1267 in_quad = (0.0 <= c0 && c0 <= 1.0 && 0.0 <= c1 && c1 <= 1.0);
1268
1269 if (in_quad)
1270 return std::make_pair(projected_shifted_p - shift,
1271 shifted_p.distance_square(projected_shifted_p));
1272 else
1273 return std::make_pair(Point<3>(), std::numeric_limits<double>::max());
1274 }
1275} // namespace
1276
1277
1278
1279template <int dim>
1282{
1283 // Handle simple cases first:
1284 if constexpr (dim == 0)
1285 return p;
1286 if (contains_point(p, 0.0))
1287 return p;
1288
1289 if constexpr (dim == 1)
1290 return project_to_line(vertex(0), vertex(1), p).first;
1291 else
1292 {
1293 // Find the closest vertex so that we only need to check adjacent faces
1294 // and lines.
1295 Point<dim> result;
1296 unsigned int closest_vertex_no = 0;
1297 double closest_vertex_distance_square = vertex(0).distance_square(p);
1298 for (unsigned int i = 1; i < n_vertices(); ++i)
1299 {
1300 const double new_vertex_distance_square =
1301 vertex(i).distance_square(p);
1302 if (new_vertex_distance_square < closest_vertex_distance_square)
1303 {
1304 closest_vertex_no = i;
1305 closest_vertex_distance_square = new_vertex_distance_square;
1306 }
1307 }
1308
1309 double min_distance_square = std::numeric_limits<double>::max();
1310 if constexpr (dim == 2)
1311 {
1312 for (const unsigned int face_no :
1313 faces_for_given_vertex(closest_vertex_no))
1314 {
1315 const Point<dim> v0 = vertex(line_to_cell_vertices(face_no, 0));
1316 const Point<dim> v1 = vertex(line_to_cell_vertices(face_no, 1));
1317
1318 auto pair = project_to_line(v0, v1, p);
1319 if (pair.second < min_distance_square)
1320 {
1321 result = pair.first;
1322 min_distance_square = pair.second;
1323 }
1324 }
1325 }
1326 else
1327 {
1328 // Check faces and then lines.
1329 //
1330 // For reference cells with sloped faces (i.e., all 3D shapes except
1331 // Hexahedra), we might be able to do a valid normal projection to a
1332 // face with a different slope which is on the 'other side' of the
1333 // reference cell. To catch that case we have to unconditionally check
1334 // lines after checking faces.
1335 //
1336 // For pyramids the closest vertex might not be on the closest face:
1337 // for example, the origin is closest to vertex 4 which is not on the
1338 // bottom plane. Get around that by just checking all faces for
1339 // pyramids.
1340 const std::array<unsigned int, 5> all_pyramid_faces{{0, 1, 2, 3, 4}};
1341 const auto &faces =
1342 *this == ReferenceCells::Pyramid ?
1343 ArrayView<const unsigned int>(all_pyramid_faces) :
1344 faces_for_given_vertex(closest_vertex_no);
1345 for (const unsigned int face_no : faces)
1346 {
1347 auto face_cell = face_reference_cell(face_no);
1348 // We only need the first three points since for quads the last
1349 // point is redundant
1350 std::array<Point<dim>, 3> vertices;
1351 for (unsigned int vertex_no = 0; vertex_no < 3; ++vertex_no)
1352 vertices[vertex_no] = vertex(face_to_cell_vertices(
1353 face_no, vertex_no, numbers::default_geometric_orientation));
1354
1355 auto pair = project_to_quad(vertices, p, face_cell);
1356 if (pair.second < min_distance_square)
1357 {
1358 result = pair.first;
1359 min_distance_square = pair.second;
1360 }
1361 }
1362
1363 for (const unsigned int face_no :
1364 faces_for_given_vertex(closest_vertex_no))
1365 {
1366 auto face_cell = face_reference_cell(face_no);
1367 for (const unsigned int face_line_no : face_cell.line_indices())
1368 {
1369 const auto cell_line_no =
1370 face_to_cell_lines(face_no,
1371 face_line_no,
1373 const auto v0 =
1374 vertex(line_to_cell_vertices(cell_line_no, 0));
1375 const auto v1 =
1376 vertex(line_to_cell_vertices(cell_line_no, 1));
1377 auto pair = project_to_line(v0, v1, p);
1378 if (pair.second < min_distance_square)
1379 {
1380 result = pair.first;
1381 min_distance_square = pair.second;
1382 }
1383 }
1384 }
1385 }
1386
1387 Assert(min_distance_square < std::numeric_limits<double>::max(),
1389
1390 // If necessary, slightly adjust the computed point so that it is closer
1391 // to being on the surface of the reference cell. Due to roundoff it is
1392 // difficult to place points on sloped surfaces (e.g., for Pyramids) so
1393 // this check isn't perfect but does improve the accuracy of the projected
1394 // point.
1395 if (!contains_point(result, 0.0))
1396 {
1397 constexpr unsigned int x_index = 0;
1398 constexpr unsigned int y_index = (dim >= 2 ? 1 : 0);
1399 constexpr unsigned int z_index = (dim >= 3 ? 2 : 0);
1400 switch (this->kind)
1401 {
1404 break;
1405 // the bounds for each dimension of a hypercube are mutually
1406 // independent:
1410 for (unsigned int d = 0; d < dim; ++d)
1411 result[d] = std::clamp(result[d], 0.0, 1.0);
1412 // simplices can use the standard definition of a simplex:
1413 break;
1415 result[x_index] = std::clamp(result[x_index], 0.0, 1.0);
1416 result[y_index] =
1417 std::clamp(result[y_index], 0.0, 1.0 - result[x_index]);
1418 break;
1420 result[x_index] = std::clamp(result[x_index], 0.0, 1.0);
1421 result[y_index] =
1422 std::clamp(result[y_index], 0.0, 1.0 - result[x_index]);
1423 result[z_index] =
1424 std::clamp(result[z_index],
1425 0.0,
1426 1.0 - result[x_index] - result[y_index]);
1427 break;
1428 // wedges and pyramids are more ad-hoc:
1430 result[x_index] = std::clamp(result[x_index], 0.0, 1.0);
1431 result[y_index] =
1432 std::clamp(result[y_index], 0.0, 1.0 - result[x_index]);
1433 result[z_index] = std::clamp(result[z_index], 0.0, 1.0);
1434 break;
1436 {
1437 result[x_index] = std::clamp(result[x_index], -1.0, 1.0);
1438 result[y_index] = std::clamp(result[y_index], -1.0, 1.0);
1439 // It suffices to transform everything to the first quadrant
1440 // to adjust z:
1441 const auto x_abs = std::abs(result[x_index]);
1442 const auto y_abs = std::abs(result[y_index]);
1443
1444 if (y_abs <= x_abs)
1445 result[z_index] =
1446 std::clamp(result[z_index], 0.0, 1.0 - x_abs);
1447 else
1448 result[z_index] =
1449 std::clamp(result[z_index], 0.0, 1.0 - y_abs);
1450 }
1451 break;
1452 default:
1454 }
1455 }
1456 // We should be within 4 * eps of the cell by this point. The roundoff
1457 // error comes from, e.g., computing (1 - x) + x when moving points onto
1458 // the top of a Pyramid.
1459 Assert(contains_point(result,
1460 4.0 * std::numeric_limits<double>::epsilon()),
1462
1463 return result;
1464 }
1465}
1466
1467
1468
1469template <int dim>
1470std::ostream &
1471operator<<(std::ostream &out, const ReferenceCell<dim> &reference_cell)
1472{
1473 AssertThrow(out.fail() == false, ExcIO());
1474
1475 // Output as an integer to avoid outputting it as a character with
1476 // potentially non-printing value:
1477 out << static_cast<unsigned int>(reference_cell.kind);
1478 return out;
1479}
1480
1481
1482
1483template <int dim>
1484std::istream &
1485operator>>(std::istream &in, ReferenceCell<dim> &reference_cell)
1486{
1487 AssertThrow(in.fail() == false, ExcIO());
1488
1489 // Read the information as an integer and convert it to the correct type
1490 unsigned int value;
1491 in >> value;
1492 reference_cell.kind = static_cast<decltype(reference_cell.kind)>(value);
1493
1494 // Ensure that the object we read is valid
1495 Assert(
1496 (reference_cell == ReferenceCells::Vertex) ||
1497 (reference_cell == ReferenceCells::Line) ||
1498 (reference_cell == ReferenceCells::Triangle) ||
1499 (reference_cell == ReferenceCells::Quadrilateral) ||
1500 (reference_cell == ReferenceCells::Tetrahedron) ||
1501 (reference_cell == ReferenceCells::Hexahedron) ||
1502 (reference_cell == ReferenceCells::Wedge) ||
1503 (reference_cell == ReferenceCells::Pyramid) ||
1504 (reference_cell == ReferenceCells::Invalid<dim>),
1505 ExcMessage(
1506 "The reference cell kind just read does not correspond to one of the "
1507 "valid choices. There must be an error."));
1508
1509 return in;
1510}
1511
1512
1513#include "grid/reference_cell.inst"
1514
1515#ifndef DOXYGEN
1516// Here also instantiate select members for dimension 0 (vertices) in addition
1517// to the general class instantiation for dim=1,2,3 in the .inst file :
1518template std::string
1520
1521template unsigned int
1523
1524template unsigned int
1526
1527template unsigned int
1529
1530template unsigned int
1532 const unsigned int vertex_index) const;
1533
1534template Quadrature<0>
1535ReferenceCell<0>::get_gauss_type_quadrature(const unsigned n_points_1d) const;
1536
1537template const Quadrature<0> &
1539
1540template std::ostream &
1541operator<<(std::ostream &out, const ReferenceCell<0> &reference_cell);
1542
1543template std::istream &
1544operator>>(std::istream &in, ReferenceCell<0> &reference_cell);
1545#endif
1546
Implementation of the classic affine transformation mapping used for simplices.
Definition mapping_p1.h:71
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
constexpr numbers::NumberTraits< Number >::real_type distance_square(const Point< dim, Number > &p) const
static constexpr Point< dim, Number > unit_vector(const unsigned int i)
unsigned int unv_vertex_to_deal_vertex(const unsigned int vertex_n) const
const Quadrature< dim > & get_nodal_type_quadrature() const
unsigned int face_to_cell_lines(const unsigned int face, const unsigned int line, const types::geometric_orientation face_orientation) const
constexpr bool is_simplex() const
constexpr unsigned int n_vertices() const
constexpr bool is_hyper_cube() const
ArrayView< const unsigned int > faces_for_given_vertex(const unsigned int vertex_index) const
unsigned int vtk_quadratic_type() const
Point< dim > closest_point(const Point< dim > &p) const
unsigned int vtk_lagrange_type() const
Quadrature< dim > get_gauss_type_quadrature(const unsigned n_points_1d) const
unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex) const
std::uint8_t kind
std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices() const
constexpr ReferenceCell< dim - 1 > face_reference_cell(const unsigned int face_index) const
unsigned int n_children(const RefinementCase< dim > ref_case=RefinementCase< dim >::isotropic_refinement) const
constexpr unsigned int n_faces() const
constexpr ReferenceCell()
unsigned int vtk_vertex_to_deal_vertex(const unsigned int vertex_index) const
Point< dim > vertex(const unsigned int v) const
std::pair< unsigned int, RefinementCase< dim - 1 > > equivalent_refinement_case(const types::geometric_orientation combined_face_orientation, const internal::SubfaceCase< dim > subface_case, const unsigned int subface_no) const
std::unique_ptr< Mapping< dim, spacedim > > get_default_mapping(const unsigned int degree) const
std::string to_string() const
unsigned int n_face_orientations(const unsigned int face_no) const
unsigned int vtk_lexicographic_to_node_index(const std::array< unsigned, dim > &node_indices, const std::array< unsigned, dim > &nodes_per_direction, const bool legacy_format) const
unsigned int gmsh_element_type() const
Point< dim > face_vertex_location(const unsigned int face, const unsigned int vertex) const
unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const types::geometric_orientation face_orientation) const
unsigned int exodusii_vertex_to_deal_vertex(const unsigned int vertex_n) const
const Mapping< dim, spacedim > & get_default_linear_mapping() const
Point< dim > subface_vertex_location(const unsigned int face_no, const unsigned int subface_no, const unsigned int subface_vertex_no, const RefinementCase< dim - 1 > face_refinement_case) const
bool contains_point(const Point< dim > &p, const double tolerance=0) const
unsigned int exodusii_face_to_deal_face(const unsigned int face_n) const
unsigned int vtk_linear_type() const
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
const bool IsBlockVector< VectorType >::value
MappingQ< dim, spacedim > StaticMappingQ1< dim, spacedim >::mapping
Definition mapping_q1.h:101
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
constexpr char V
constexpr ReferenceCell< 3 > Hexahedron
constexpr ReferenceCell< 2 > Quadrilateral
constexpr ReferenceCell< 1 > Line
constexpr ReferenceCell< 2 > Triangle
constexpr ReferenceCell< 3 > Tetrahedron
constexpr ReferenceCell< dim > Invalid
constexpr ReferenceCell< 3 > Pyramid
constexpr ReferenceCell< 3 > Wedge
constexpr ReferenceCell< 0 > Vertex
std::tuple< bool, bool, bool > split_face_orientation(const types::geometric_orientation combined_orientation)
constexpr unsigned int invalid_unsigned_int
Definition types.h:236
constexpr types::geometric_orientation reverse_line_orientation
Definition types.h:363
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:350
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
std::uint8_t geometric_orientation
Definition types.h:38
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray
Definition ndarray.h:105
std::istream & operator>>(std::istream &in, ReferenceCell< dim > &reference_cell)
std::ostream & operator<<(std::ostream &out, const ReferenceCell< dim > &reference_cell)
static unsigned int child_cell_on_face(const RefinementCase< dim > &ref_case, const unsigned int face, const unsigned int subface, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false, const RefinementCase< dim - 1 > &face_refinement_case=RefinementCase< dim - 1 >::isotropic_refinement)
static constexpr unsigned int max_children_per_face
static MappingQ< dim, spacedim > mapping
Definition mapping_q1.h:94
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)