deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\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
hanging_nodes_internal.h
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) 2018 - 2025 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
13#ifndef dealii_hanging_nodes_internal_h
14#define dealii_hanging_nodes_internal_h
15
16#include <deal.II/base/config.h>
17
20
22
23#include <deal.II/fe/fe_q.h>
25#include <deal.II/fe/fe_tools.h>
26
28
29#include <boost/container/small_vector.hpp>
30
31
33
34namespace internal
35{
36 namespace MatrixFreeFunctions
37 {
51 enum class ConstraintKinds : std::uint16_t
52 {
53 // default: unconstrained cell
54 unconstrained = 0,
55
56 // subcell
57 subcell_x = 1 << 0,
58 subcell_y = 1 << 1,
59 subcell_z = 1 << 2,
60
61 // face is constrained
62 face_x = 1 << 3,
63 face_y = 1 << 4,
64 face_z = 1 << 5,
65
66 // edge is constrained
67 edge_x = 1 << 6,
68 edge_y = 1 << 7,
69 edge_z = 1 << 8
70 };
71
72
73
77 using compressed_constraint_kind = std::uint8_t;
78
79
80
86
87
88
92 inline bool
93 check(const ConstraintKinds kind_in, const unsigned int dim)
94 {
95 const std::uint16_t kind = static_cast<std::uint16_t>(kind_in);
96 const std::uint16_t subcell = (kind >> 0) & 7;
97 const std::uint16_t face = (kind >> 3) & 7;
98 const std::uint16_t edge = (kind >> 6) & 7;
99
100 if ((kind >> 9) > 0)
101 return false;
102
103 if (dim == 2)
104 {
105 if (edge > 0)
106 return false; // in 2d there are no edge constraints
107
108 if (subcell == 0 && face == 0)
109 return true; // no constraints
110 else if (0 < face)
111 return true; // at least one face is constrained
112 }
113 else if (dim == 3)
114 {
115 if (subcell == 0 && face == 0 && edge == 0)
116 return true; // no constraints
117 else if (0 < face && edge == 0)
118 return true; // at least one face is constrained
119 else if (0 == face && 0 < edge)
120 return true; // at least one edge is constrained
121 else if ((face == edge) && (face == 1 || face == 2 || face == 4))
122 return true; // one face and its orthogonal edge is constrained
123 }
124
125 return false;
126 }
127
128
129
135 compress(const ConstraintKinds kind_in, const unsigned int dim)
136 {
137 Assert(check(kind_in, dim), ExcInternalError());
138
139 if (dim == 2)
140 return static_cast<compressed_constraint_kind>(kind_in);
141
142 if (kind_in == ConstraintKinds::unconstrained)
144
145 const std::uint16_t kind = static_cast<std::uint16_t>(kind_in);
146 const std::uint16_t subcell = (kind >> 0) & 7;
147 const std::uint16_t face = (kind >> 3) & 7;
148 const std::uint16_t edge = (kind >> 6) & 7;
149
150 return subcell + ((face > 0) << 3) + ((edge > 0) << 4) +
151 (std::max(face, edge) << 5);
152 }
153
154
155
160 inline ConstraintKinds
161 decompress(const compressed_constraint_kind kind_in, const unsigned int dim)
162 {
163 if (dim == 2)
164 return static_cast<ConstraintKinds>(kind_in);
165
168
169 const std::uint16_t subcell = (kind_in >> 0) & 7;
170 const std::uint16_t flag_0 = (kind_in >> 3) & 3;
171 const std::uint16_t flag_1 = (kind_in >> 5) & 7;
172
173 const auto result = static_cast<ConstraintKinds>(
174 subcell + (((flag_0 & 0b01) ? flag_1 : 0) << 3) +
175 (((flag_0 & 0b10) ? flag_1 : 0) << 6));
176
177 Assert(check(result, dim), ExcInternalError());
178
179 return result;
180 }
181
182
183
187 inline std::size_t
189 {
190 return sizeof(ConstraintKinds);
191 }
192
193
194
204 {
205 return static_cast<ConstraintKinds>(static_cast<std::uint16_t>(f1) |
206 static_cast<std::uint16_t>(f2));
207 }
208
209
210
217 {
218 f1 = f1 | f2;
219 return f1;
220 }
221
222
223
227 DEAL_II_HOST_DEVICE inline bool
229 {
230 return static_cast<std::uint16_t>(f1) != static_cast<std::uint16_t>(f2);
231 }
232
233
234
240 operator<(const ConstraintKinds f1, const ConstraintKinds f2)
241 {
242 return static_cast<std::uint16_t>(f1) < static_cast<std::uint16_t>(f2);
243 }
244
245
246
252 {
253 return static_cast<ConstraintKinds>(static_cast<std::uint16_t>(f1) &
254 static_cast<std::uint16_t>(f2));
255 }
256
257
258
265 template <int dim>
267 {
268 public:
272 HangingNodes(const Triangulation<dim> &triangualtion);
273
277 std::size_t
278 memory_consumption() const;
279
283 template <typename CellIterator>
284 bool
286 const CellIterator &cell,
287 const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
288 const std::vector<std::vector<unsigned int>> &lexicographic_mapping,
289 std::vector<types::global_dof_index> &dof_indices,
290 const ArrayView<ConstraintKinds> &mask) const;
291
296 static std::vector<std::vector<bool>>
297 compute_supported_components(const ::hp::FECollection<dim> &fe);
298
302 template <typename CellIterator>
304 compute_refinement_configuration(const CellIterator &cell) const;
305
310 template <typename CellIterator>
311 void
313 const CellIterator &cell,
314 const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
315 const std::vector<std::vector<unsigned int>> &lexicographic_mapping,
316 const std::vector<std::vector<bool>> &component_mask,
317 const ConstraintKinds &refinement_configuration,
318 std::vector<types::global_dof_index> &dof_indices) const;
319
320 private:
324 void
325 setup_line_to_cell(const Triangulation<dim> &triangulation);
326
327 void
328 rotate_subface_index(int times, unsigned int &subface_index) const;
329
330 void
331 orient_face(const types::geometric_orientation combined_orientation,
332 const unsigned int n_dofs_1d,
333 std::vector<types::global_dof_index> &dofs) const;
334
335 unsigned int
336 line_dof_idx(int local_line,
337 unsigned int dof,
338 unsigned int n_dofs_1d) const;
339
340 void
341 transpose_subface_index(unsigned int &subface) const;
342
343 std::vector<
344 boost::container::small_vector<std::array<unsigned int, 3>, 6>>
346
347 const ::ndarray<unsigned int, 3, 2, 2> local_lines = {
348 {{{{{7, 3}}, {{6, 2}}}},
349 {{{{5, 1}}, {{4, 0}}}},
350 {{{{11, 9}}, {{10, 8}}}}}};
351 };
352
353
354
355 template <int dim>
357 const Triangulation<dim> &triangulation)
358 {
359 // Set up line-to-cell mapping for edge constraints (only if dim = 3 and
360 // for pure hex meshes)
361 if (triangulation.all_reference_cells_are_hyper_cube())
362 setup_line_to_cell(triangulation);
363 }
364
365
366
367 template <int dim>
368 inline std::size_t
370 {
371 std::size_t size = 0;
372 for (const auto &a : line_to_cells)
373 size +=
374 (a.capacity() > 6 ? a.capacity() : 0) * sizeof(a[0]) + sizeof(a);
375 return size;
376 }
377
378
379
380 template <int dim>
381 inline void
383 const Triangulation<dim> & /*triangulation*/)
384 {}
385
386
387
388 template <>
389 inline void
391 {
392 // Check if we there are no hanging nodes on the current MPI process,
393 // which we do by checking if the second finest level holds no active
394 // non-artificial cell
395 if (triangulation.n_levels() <= 1 ||
396 std::none_of(triangulation.begin_active(triangulation.n_levels() - 2),
397 triangulation.end_active(triangulation.n_levels() - 2),
398 [](const CellAccessor<3, 3> &cell) {
399 return !cell.is_artificial();
400 }))
401 return;
402
403 const unsigned int n_raw_lines = triangulation.n_raw_lines();
404 this->line_to_cells.resize(n_raw_lines);
405
406 // In 3d, we can have DoFs on only an edge being constrained (e.g. in a
407 // cartesian 2x2x2 grid, where only the upper left 2 cells are refined).
408 // This sets up a helper data structure in the form of a mapping from
409 // edges (i.e. lines) to neighboring cells.
410
411 // Mapping from an edge to which children that share that edge.
412 const unsigned int line_to_children[12][2] = {{0, 2},
413 {1, 3},
414 {0, 1},
415 {2, 3},
416 {4, 6},
417 {5, 7},
418 {4, 5},
419 {6, 7},
420 {0, 4},
421 {1, 5},
422 {2, 6},
423 {3, 7}};
424
425 std::vector<
426 boost::container::small_vector<std::array<unsigned int, 3>, 6>>
427 line_to_inactive_cells(n_raw_lines);
428
429 // First add active and inactive cells to their lines:
430 for (const auto &cell : triangulation.cell_iterators())
431 {
432 const unsigned int cell_level = cell->level();
433 const unsigned int cell_index = cell->index();
434 for (unsigned int line = 0; line < GeometryInfo<3>::lines_per_cell;
435 ++line)
436 {
437 const unsigned int line_idx = cell->line_index(line);
438 if (cell->is_active())
439 line_to_cells[line_idx].push_back(
440 {{cell_level, cell_index, line}});
441 else
442 line_to_inactive_cells[line_idx].push_back(
443 {{cell_level, cell_index, line}});
444 }
445 }
446
447 // Now, we can access edge-neighboring active cells on same level to also
448 // access of an edge to the edges "children". These are found from looking
449 // at the corresponding edge of children of inactive edge neighbors.
450 for (unsigned int line_idx = 0; line_idx < n_raw_lines; ++line_idx)
451 {
452 if ((line_to_cells[line_idx].size() > 0) &&
453 line_to_inactive_cells[line_idx].size() > 0)
454 {
455 // We now have cells to add (active ones) and edges to which they
456 // should be added (inactive cells).
457 const Triangulation<3>::cell_iterator inactive_cell(
458 &triangulation,
459 line_to_inactive_cells[line_idx][0][0],
460 line_to_inactive_cells[line_idx][0][1]);
461 const unsigned int neighbor_line =
462 line_to_inactive_cells[line_idx][0][2];
463
464 for (unsigned int c = 0; c < 2; ++c)
465 {
466 const auto &child =
467 inactive_cell->child(line_to_children[neighbor_line][c]);
468 const unsigned int child_line_idx =
469 child->line_index(neighbor_line);
470
471 Assert(child->is_active(), ExcInternalError());
472
473 // Now add all active cells
474 for (const auto &cl : line_to_cells[line_idx])
475 line_to_cells[child_line_idx].push_back(cl);
476 }
477 }
478 }
479 }
480
481
482
483 template <int dim>
484 inline std::vector<std::vector<bool>>
486 const ::hp::FECollection<dim> &fe_collection)
487 {
488 std::vector<std::vector<bool>> supported_components(
489 fe_collection.size(),
490 std::vector<bool>(fe_collection.n_components(), false));
491
492 for (unsigned int i = 0; i < fe_collection.size(); ++i)
493 {
494 for (unsigned int base_element_index = 0, comp = 0;
495 base_element_index < fe_collection[i].n_base_elements();
496 ++base_element_index)
497 for (unsigned int c = 0;
498 c < fe_collection[i].element_multiplicity(base_element_index);
499 ++c, ++comp)
500 if (dim == 1 ||
501 (dynamic_cast<const FE_Q<dim> *>(
502 &fe_collection[i].base_element(base_element_index)) ==
503 nullptr &&
504 dynamic_cast<const FE_Q_iso_Q1<dim> *>(
505 &fe_collection[i].base_element(base_element_index)) ==
506 nullptr))
507 supported_components[i][comp] = false;
508 else
509 supported_components[i][comp] = true;
510 }
511
512 return supported_components;
513 }
514
515
516
517 template <int dim>
518 template <typename CellIterator>
519 inline ConstraintKinds
521 const CellIterator &cell) const
522 {
523 // TODO: for simplex or mixed meshes: nothing to do
524 if ((dim == 3 && line_to_cells.empty()) ||
525 (cell->reference_cell().is_hyper_cube() == false))
527
528 if (cell->level() == 0)
530
531 const std::uint16_t subcell =
532 cell->parent()->child_iterator_to_index(cell);
533 const std::uint16_t subcell_x = (subcell >> 0) & 1;
534 const std::uint16_t subcell_y = (subcell >> 1) & 1;
535 const std::uint16_t subcell_z = (subcell >> 2) & 1;
536
537 std::uint16_t face = 0;
538 std::uint16_t edge = 0;
539
540 for (unsigned int direction = 0; direction < dim; ++direction)
541 {
542 const auto side = (subcell >> direction) & 1U;
543 const auto face_no = direction * 2 + side;
544
545 // ignore if at boundary
546 if (cell->at_boundary(face_no))
547 continue;
548
549 const auto &neighbor = cell->neighbor(face_no);
550
551 // ignore neighbors that are artificial or have the same level or
552 // have children
553 if (neighbor->has_children() || neighbor->is_artificial() ||
554 neighbor->level() == cell->level())
555 continue;
556
557 // Ignore if the neighbors are FE_Nothing
558 if (neighbor->get_fe().n_dofs_per_cell() == 0)
559 continue;
560
561 face |= 1 << direction;
562 }
563
564 if (dim == 3)
565 for (unsigned int direction = 0; direction < dim; ++direction)
566 if (face == 0 || face == (1 << direction))
567 {
568 const unsigned int line_no =
569 direction == 0 ?
570 (local_lines[0][subcell_y == 0][subcell_z == 0]) :
571 (direction == 1 ?
572 (local_lines[1][subcell_x == 0][subcell_z == 0]) :
573 (local_lines[2][subcell_x == 0][subcell_y == 0]));
574
575 const unsigned int line_index = cell->line_index(line_no);
576
577 const auto edge_neighbor =
578 std::find_if(line_to_cells[line_index].begin(),
579 line_to_cells[line_index].end(),
580 [&cell](const auto &edge_neighbor) {
582 &cell->get_triangulation(),
583 edge_neighbor[0],
584 edge_neighbor[1],
585 &cell->get_dof_handler());
586 return dof_cell.is_artificial() == false &&
587 dof_cell.level() < cell->level() &&
588 dof_cell.get_fe().n_dofs_per_cell() > 0;
589 });
590
591 if (edge_neighbor == line_to_cells[line_index].end())
592 continue;
593
594 edge |= 1 << direction;
595 }
596
597 if ((face == 0) && (edge == 0))
599
600 const std::uint16_t inverted_subcell = (subcell ^ (dim == 2 ? 3 : 7));
601
602 const auto refinement_configuration = static_cast<ConstraintKinds>(
603 inverted_subcell + (face << 3) + (edge << 6));
604 Assert(check(refinement_configuration, dim), ExcInternalError());
605 return refinement_configuration;
606 }
607
608
609
610 template <int dim>
611 template <typename CellIterator>
612 inline void
614 const CellIterator &cell,
615 const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
616 const std::vector<std::vector<unsigned int>> &lexicographic_mapping,
617 const std::vector<std::vector<bool>> &supported_components,
618 const ConstraintKinds &refinement_configuration,
619 std::vector<types::global_dof_index> &dof_indices) const
620 {
621 if (std::find(supported_components[cell->active_fe_index()].begin(),
622 supported_components[cell->active_fe_index()].end(),
623 true) ==
624 supported_components[cell->active_fe_index()].end())
625 return;
626
627 const auto &fe = cell->get_fe();
628 AssertDimension(fe.n_unique_faces(), 1);
629
630 std::vector<std::vector<unsigned int>>
631 component_to_system_index_face_array(fe.n_components());
632
633 for (unsigned int i = 0; i < fe.n_dofs_per_face(0); ++i)
634 component_to_system_index_face_array
635 [fe.face_system_to_component_index(i, /*face_no=*/0).first]
636 .push_back(i);
637
638 std::vector<unsigned int> idx_offset = {0};
639
640 for (unsigned int base_element_index = 0;
641 base_element_index < fe.n_base_elements();
642 ++base_element_index)
643 for (unsigned int c = 0;
644 c < fe.element_multiplicity(base_element_index);
645 ++c)
646 idx_offset.push_back(
647 idx_offset.back() +
648 fe.base_element(base_element_index).n_dofs_per_cell());
649
650 std::vector<types::global_dof_index> neighbor_dofs_all(idx_offset.back());
651 std::vector<types::global_dof_index> neighbor_dofs_all_temp(
652 idx_offset.back());
653 std::vector<types::global_dof_index> neighbor_dofs_face(
654 fe.n_dofs_per_face(/*face_no=*/0));
655
656
657 const auto get_face_idx = [](const auto n_dofs_1d,
658 const auto face_no,
659 const auto i,
660 const auto j) -> unsigned int {
661 const auto direction = face_no / 2;
662 const auto side = face_no % 2;
663 const auto offset = (side == 1) ? (n_dofs_1d - 1) : 0;
664
665 if (dim == 2)
666 return (direction == 0) ? (n_dofs_1d * i + offset) :
667 (n_dofs_1d * offset + i);
668 else if (dim == 3)
669 switch (direction)
670 {
671 case 0:
672 return n_dofs_1d * n_dofs_1d * i + n_dofs_1d * j + offset;
673 case 1:
674 return n_dofs_1d * n_dofs_1d * j + n_dofs_1d * offset + i;
675 case 2:
676 return n_dofs_1d * n_dofs_1d * offset + n_dofs_1d * i + j;
677 default:
679 }
680
682
683 return 0;
684 };
685
686 const std::uint16_t kind =
687 static_cast<std::uint16_t>(refinement_configuration);
688 const std::uint16_t subcell = (kind >> 0) & 7;
689 const std::uint16_t subcell_x = (subcell >> 0) & 1;
690 const std::uint16_t subcell_y = (subcell >> 1) & 1;
691 const std::uint16_t subcell_z = (subcell >> 2) & 1;
692 const std::uint16_t face = (kind >> 3) & 7;
693 const std::uint16_t edge = (kind >> 6) & 7;
694
695 for (unsigned int direction = 0; direction < dim; ++direction)
696 if ((face >> direction) & 1U)
697 {
698 const auto side = ((subcell >> direction) & 1U) == 0;
699 const auto face_no = direction * 2 + side;
700
701 // read DoFs of parent of face, ...
702 cell->neighbor(face_no)
703 ->face(cell->neighbor_face_no(face_no))
704 ->get_dof_indices(neighbor_dofs_face,
705 cell->neighbor(face_no)->active_fe_index());
706
707 // ... convert the global DoFs to serial ones, and ...
708 if (partitioner)
709 for (auto &index : neighbor_dofs_face)
710 index = partitioner->global_to_local(index);
711
712 for (unsigned int base_element_index = 0, comp = 0;
713 base_element_index < fe.n_base_elements();
714 ++base_element_index)
715 for (unsigned int c = 0;
716 c < fe.element_multiplicity(base_element_index);
717 ++c, ++comp)
718 {
719 if (supported_components[cell->active_fe_index()][comp] ==
720 false)
721 continue;
722
723 const unsigned int n_dofs_1d =
724 cell->get_fe()
725 .base_element(base_element_index)
726 .tensor_degree() +
727 1;
728 const unsigned int dofs_per_face =
729 Utilities::pow(n_dofs_1d, dim - 1);
730 std::vector<types::global_dof_index> neighbor_dofs(
731 dofs_per_face);
732 const auto lex_face_mapping =
734 n_dofs_1d - 1);
735
736 // ... extract the DoFs of the current component
737 for (unsigned int i = 0; i < dofs_per_face; ++i)
738 neighbor_dofs[i] = neighbor_dofs_face
739 [component_to_system_index_face_array[comp][i]];
740
741 // fix DoFs depending on orientation, rotation, and flip
742 if (dim == 2)
743 {
744 // TODO: this needs to be implemented for simplices but
745 // all-quad meshes are OK
746 Assert(cell->combined_face_orientation(face_no) ==
749 }
750 else if (dim == 3)
751 {
752 orient_face(cell->combined_face_orientation(face_no),
753 n_dofs_1d,
754 neighbor_dofs);
755 }
756 else
757 {
759 }
760
761 // update DoF map
762 for (unsigned int i = 0, k = 0; i < n_dofs_1d; ++i)
763 for (unsigned int j = 0; j < (dim == 2 ? 1 : n_dofs_1d);
764 ++j, ++k)
765 dof_indices[get_face_idx(n_dofs_1d, face_no, i, j) +
766 idx_offset[comp]] =
767 neighbor_dofs[lex_face_mapping[k]];
768 }
769 }
770
771 if (dim == 3)
772 for (unsigned int direction = 0; direction < dim; ++direction)
773 if ((edge >> direction) & 1U)
774 {
775 const unsigned int line_no =
776 direction == 0 ?
777 (local_lines[0][subcell_y][subcell_z]) :
778 (direction == 1 ? (local_lines[1][subcell_x][subcell_z]) :
779 (local_lines[2][subcell_x][subcell_y]));
780
781 const unsigned int line_index = cell->line(line_no)->index();
782
783 const auto edge_neighbor =
784 std::find_if(line_to_cells[line_index].begin(),
785 line_to_cells[line_index].end(),
786 [&cell](const auto &edge_array) {
788 edge_neighbor(&cell->get_triangulation(),
789 edge_array[0],
790 edge_array[1]);
791 return edge_neighbor->is_artificial() == false &&
792 edge_neighbor->level() < cell->level();
793 });
794
795 if (edge_neighbor == line_to_cells[line_index].end())
796 continue;
797
798 const DoFCellAccessor<dim, dim, false> neighbor_cell(
799 &cell->get_triangulation(),
800 (*edge_neighbor)[0],
801 (*edge_neighbor)[1],
802 &cell->get_dof_handler());
803 const auto local_line_neighbor = (*edge_neighbor)[2];
804
805 neighbor_cell.get_dof_indices(neighbor_dofs_all);
806
807 if (partitioner)
808 for (auto &index : neighbor_dofs_all)
809 index = partitioner->global_to_local(index);
810
811 for (unsigned int i = 0; i < neighbor_dofs_all_temp.size(); ++i)
812 neighbor_dofs_all_temp[i] = neighbor_dofs_all
813 [lexicographic_mapping[cell->active_fe_index()][i]];
814
815 const bool flipped =
816 cell->line_orientation(line_no) !=
817 neighbor_cell.line_orientation(local_line_neighbor);
818
819 for (unsigned int base_element_index = 0, comp = 0;
820 base_element_index < fe.n_base_elements();
821 ++base_element_index)
822 for (unsigned int c = 0;
823 c < fe.element_multiplicity(base_element_index);
824 ++c, ++comp)
825 {
826 if (supported_components[cell->active_fe_index()][comp] ==
827 false)
828 continue;
829
830 const unsigned int n_dofs_1d =
831 cell->get_fe()
832 .base_element(base_element_index)
833 .tensor_degree() +
834 1;
835
836 for (unsigned int i = 0; i < n_dofs_1d; ++i)
837 dof_indices[line_dof_idx(line_no, i, n_dofs_1d) +
838 idx_offset[comp]] = neighbor_dofs_all_temp
839 [line_dof_idx(local_line_neighbor,
840 flipped ? (n_dofs_1d - 1 - i) : i,
841 n_dofs_1d) +
842 idx_offset[comp]];
843 }
844 }
845 }
846
847
848
849 template <int dim>
850 template <typename CellIterator>
851 inline bool
853 const CellIterator &cell,
854 const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
855 const std::vector<std::vector<unsigned int>> &lexicographic_mapping,
856 std::vector<types::global_dof_index> &dof_indices,
857 const ArrayView<ConstraintKinds> &masks) const
858 {
859 // 1) check if finite elements support fast hanging-node algorithm
860 const auto supported_components = compute_supported_components(
861 cell->get_dof_handler().get_fe_collection());
862
863 if (std::none_of(supported_components.begin(),
864 supported_components.end(),
865 [](const auto &a) {
866 return *std::max_element(a.begin(), a.end());
867 }))
868 return false;
869
870 // 2) determine the refinement configuration of the cell
871 const auto refinement_configuration =
872 compute_refinement_configuration(cell);
873
874 if (refinement_configuration == ConstraintKinds::unconstrained)
875 return false;
876
877 // 3) update DoF indices of cell for specified components
878 update_dof_indices(cell,
879 partitioner,
880 lexicographic_mapping,
881 supported_components,
882 refinement_configuration,
883 dof_indices);
884
885 // 4) TODO: copy refinement configuration to all components
886 for (unsigned int c = 0; c < supported_components[0].size(); ++c)
887 if (supported_components[cell->active_fe_index()][c])
888 masks[c] = refinement_configuration;
889
890 return true;
891 }
892
893
894
895 template <int dim>
896 inline void
898 unsigned int &subface_index) const
899 {
900 const unsigned int rot_mapping[4] = {2, 0, 3, 1};
901
902 times = times % 4;
903 times = times < 0 ? times + 4 : times;
904 for (int t = 0; t < times; ++t)
905 subface_index = rot_mapping[subface_index];
906 }
907
908
909
910 template <int dim>
911 inline void
913 const types::geometric_orientation combined_orientation,
914 const unsigned int n_dofs_1d,
915 std::vector<types::global_dof_index> &dofs) const
916 {
917 const auto [orientation, rotation, flip] =
918 ::internal::split_face_orientation(combined_orientation);
919 const int n_rotations =
920 rotation || flip ? 4 - int(rotation) - 2 * int(flip) : 0;
921
922 const unsigned int rot_mapping[4] = {2, 0, 3, 1};
923 Assert(n_dofs_1d > 1, ExcInternalError());
924 // 'per line' has the same meaning here as in FiniteElementData, i.e., the
925 // number of dofs assigned to a line (not including vertices).
926 const unsigned int dofs_per_line = n_dofs_1d - 2;
927
928 // rotate:
929 std::vector<types::global_dof_index> copy(dofs.size());
930 for (int t = 0; t < n_rotations; ++t)
931 {
932 std::swap(copy, dofs);
933
934 // Vertices
935 for (unsigned int i = 0; i < 4; ++i)
936 dofs[rot_mapping[i]] = copy[i];
937
938 // Edges
939 unsigned int offset = 4;
940 for (unsigned int i = 0; i < dofs_per_line; ++i)
941 {
942 // Left edge
943 dofs[offset + i] =
944 copy[offset + 2 * dofs_per_line + (dofs_per_line - 1 - i)];
945 // Right edge
946 dofs[offset + dofs_per_line + i] =
947 copy[offset + 3 * dofs_per_line + (dofs_per_line - 1 - i)];
948 // Bottom edge
949 dofs[offset + 2 * dofs_per_line + i] =
950 copy[offset + dofs_per_line + i];
951 // Top edge
952 dofs[offset + 3 * dofs_per_line + i] = copy[offset + i];
953 }
954
955 // Interior points
956 offset += 4 * dofs_per_line;
957
958 for (unsigned int i = 0; i < dofs_per_line; ++i)
959 for (unsigned int j = 0; j < dofs_per_line; ++j)
960 dofs[offset + i * dofs_per_line + j] =
961 copy[offset + j * dofs_per_line + (dofs_per_line - 1 - i)];
962 }
963
964 // transpose (note that we are using the standard geometric orientation
965 // here so orientation = true is the default):
966 if (!orientation)
967 {
968 copy = dofs;
969
970 // Vertices
971 dofs[1] = copy[2];
972 dofs[2] = copy[1];
973
974 // Edges
975 unsigned int offset = 4;
976 for (unsigned int i = 0; i < dofs_per_line; ++i)
977 {
978 // Right edge
979 dofs[offset + i] = copy[offset + 2 * dofs_per_line + i];
980 // Left edge
981 dofs[offset + dofs_per_line + i] =
982 copy[offset + 3 * dofs_per_line + i];
983 // Bottom edge
984 dofs[offset + 2 * dofs_per_line + i] = copy[offset + i];
985 // Top edge
986 dofs[offset + 3 * dofs_per_line + i] =
987 copy[offset + dofs_per_line + i];
988 }
989
990 // Interior
991 offset += 4 * dofs_per_line;
992 for (unsigned int i = 0; i < dofs_per_line; ++i)
993 for (unsigned int j = 0; j < dofs_per_line; ++j)
994 dofs[offset + i * dofs_per_line + j] =
995 copy[offset + j * dofs_per_line + i];
996 }
997 }
998
999
1000
1001 template <int dim>
1002 inline unsigned int
1004 unsigned int dof,
1005 unsigned int n_dofs_1d) const
1006 {
1007 unsigned int x, y, z;
1008
1009 const unsigned int fe_degree = n_dofs_1d - 1;
1010
1011 if (local_line < 8)
1012 {
1013 x = (local_line % 4 == 0) ? 0 :
1014 (local_line % 4 == 1) ? fe_degree :
1015 dof;
1016 y = (local_line % 4 == 2) ? 0 :
1017 (local_line % 4 == 3) ? fe_degree :
1018 dof;
1019 z = (local_line / 4) * fe_degree;
1020 }
1021 else
1022 {
1023 x = ((local_line - 8) % 2) * fe_degree;
1024 y = ((local_line - 8) / 2) * fe_degree;
1025 z = dof;
1026 }
1027
1028 return n_dofs_1d * n_dofs_1d * z + n_dofs_1d * y + x;
1029 }
1030
1031
1032
1033 template <int dim>
1034 void
1036 {
1037 if (subface == 1)
1038 subface = 2;
1039 else if (subface == 2)
1040 subface = 1;
1041 }
1042 } // namespace MatrixFreeFunctions
1043} // namespace internal
1044
1045
1047
1048#endif
*  iterator end()
*  *  iterator begin()
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
bool is_active() const
const FiniteElement< dimension_, space_dimension_ > & get_fe() const
void get_dof_indices(std::vector< types::global_dof_index > &dof_indices) const
Definition fe_q.h:552
int index() const
int level() const
unsigned int line_index(const unsigned int i) const
bool all_reference_cells_are_hyper_cube() const
unsigned int n_raw_lines() const
unsigned int n_levels() const
active_cell_iterator end_active(const unsigned int level) const
active_cell_iterator begin_active(const unsigned int level=0) const
ConstraintKinds compute_refinement_configuration(const CellIterator &cell) const
void setup_line_to_cell(const Triangulation< dim > &triangulation)
void orient_face(const types::geometric_orientation combined_orientation, const unsigned int n_dofs_1d, std::vector< types::global_dof_index > &dofs) const
std::vector< boost::container::small_vector< std::array< unsigned int, 3 >, 6 > > line_to_cells
static std::vector< std::vector< bool > > compute_supported_components(const ::hp::FECollection< dim > &fe)
HangingNodes(const Triangulation< dim > &triangualtion)
bool setup_constraints(const CellIterator &cell, const std::shared_ptr< const Utilities::MPI::Partitioner > &partitioner, const std::vector< std::vector< unsigned int > > &lexicographic_mapping, std::vector< types::global_dof_index > &dof_indices, const ArrayView< ConstraintKinds > &mask) const
void transpose_subface_index(unsigned int &subface) const
unsigned int line_dof_idx(int local_line, unsigned int dof, unsigned int n_dofs_1d) const
void update_dof_indices(const CellIterator &cell, const std::shared_ptr< const Utilities::MPI::Partitioner > &partitioner, const std::vector< std::vector< unsigned int > > &lexicographic_mapping, const std::vector< std::vector< bool > > &component_mask, const ConstraintKinds &refinement_configuration, std::vector< types::global_dof_index > &dof_indices) const
const ::ndarray< unsigned int, 3, 2, 2 > local_lines
void rotate_subface_index(int times, unsigned int &subface_index) const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_HOST_DEVICE
Definition config.h:171
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int cell_index
IteratorRange< cell_iterator > cell_iterators() const
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
std::size_t size
Definition mpi.cc:733
std::vector< unsigned int > lexicographic_to_hierarchic_numbering(unsigned int degree)
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
bool operator<(const ConstraintKinds f1, const ConstraintKinds f2)
ConstraintKinds decompress(const compressed_constraint_kind kind_in, const unsigned int dim)
bool check(const ConstraintKinds kind_in, const unsigned int dim)
compressed_constraint_kind compress(const ConstraintKinds kind_in, const unsigned int dim)
ConstraintKinds & operator|=(ConstraintKinds &f1, const ConstraintKinds f2)
std::size_t memory_consumption(const ConstraintKinds &)
std::uint8_t compressed_constraint_kind
Definition dof_info.h:84
ConstraintKinds operator&(const ConstraintKinds f1, const ConstraintKinds f2)
bool operator!=(const ConstraintKinds f1, const ConstraintKinds f2)
constexpr compressed_constraint_kind unconstrained_compressed_constraint_kind
ConstraintKinds operator|(const ConstraintKinds f1, const ConstraintKinds f2)
std::tuple< bool, bool, bool > split_face_orientation(const types::geometric_orientation combined_orientation)
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
std::uint8_t geometric_orientation
Definition types.h:38