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
dof_handler.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) 1998 - 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
13#include <deal.II/base/config.h>
14
17#include <deal.II/base/mpi.templates.h>
19
20#include <deal.II/distributed/cell_data_transfer.templates.h>
24
27
30#include <deal.II/grid/tria.h>
34
35#include <algorithm>
36#include <memory>
37#include <set>
38#include <unordered_set>
39
41
42#ifndef DOXYGEN
43template <int dim, int spacedim>
46#endif
47
48namespace internal
49{
50 template <int dim, int spacedim>
51 std::string
52 policy_to_string(const ::internal::DoFHandlerImplementation::Policy::
53 PolicyBase<dim, spacedim> &policy)
54 {
55 std::string policy_name;
56 if (dynamic_cast<const typename ::internal::DoFHandlerImplementation::
57 Policy::Sequential<dim, spacedim> *>(&policy))
58 policy_name = "Policy::Sequential<";
59 else if (dynamic_cast<
60 const typename ::internal::DoFHandlerImplementation::
61 Policy::ParallelDistributed<dim, spacedim> *>(&policy))
62 policy_name = "Policy::ParallelDistributed<";
63 else if (dynamic_cast<
64 const typename ::internal::DoFHandlerImplementation::
65 Policy::ParallelShared<dim, spacedim> *>(&policy))
66 policy_name = "Policy::ParallelShared<";
67 else
69 policy_name += Utilities::int_to_string(dim) + "," +
70 Utilities::int_to_string(spacedim) + ">";
71 return policy_name;
72 }
73
74
75 namespace DoFHandlerImplementation
76 {
82 {
87 template <int spacedim>
88 static unsigned int
90 {
91 return std::min(static_cast<types::global_dof_index>(
92 3 * dof_handler.fe_collection.max_dofs_per_vertex() +
93 2 * dof_handler.fe_collection.max_dofs_per_line()),
94 dof_handler.n_dofs());
95 }
96
97 template <int spacedim>
98 static unsigned int
100 {
101 // get these numbers by drawing pictures
102 // and counting...
103 // example:
104 // | | |
105 // --x-----x--x--X--
106 // | | | |
107 // | x--x--x
108 // | | | |
109 // --x--x--*--x--x--
110 // | | | |
111 // x--x--x |
112 // | | | |
113 // --X--x--x-----x--
114 // | | |
115 // x = vertices connected with center vertex *;
116 // = total of 19
117 // (the X vertices are connected with * if
118 // the vertices adjacent to X are hanging
119 // nodes)
120 // count lines -> 28 (don't forget to count
121 // mother and children separately!)
122 types::global_dof_index max_couplings;
123 switch (dof_handler.tria->max_adjacent_cells())
124 {
125 case 4:
126 max_couplings =
127 19 * dof_handler.fe_collection.max_dofs_per_vertex() +
128 28 * dof_handler.fe_collection.max_dofs_per_line() +
129 8 * dof_handler.fe_collection.max_dofs_per_quad();
130 break;
131 case 5:
132 max_couplings =
133 21 * dof_handler.fe_collection.max_dofs_per_vertex() +
134 31 * dof_handler.fe_collection.max_dofs_per_line() +
135 9 * dof_handler.fe_collection.max_dofs_per_quad();
136 break;
137 case 6:
138 max_couplings =
139 28 * dof_handler.fe_collection.max_dofs_per_vertex() +
140 42 * dof_handler.fe_collection.max_dofs_per_line() +
141 12 * dof_handler.fe_collection.max_dofs_per_quad();
142 break;
143 case 7:
144 max_couplings =
145 30 * dof_handler.fe_collection.max_dofs_per_vertex() +
146 45 * dof_handler.fe_collection.max_dofs_per_line() +
147 13 * dof_handler.fe_collection.max_dofs_per_quad();
148 break;
149 case 8:
150 max_couplings =
151 37 * dof_handler.fe_collection.max_dofs_per_vertex() +
152 56 * dof_handler.fe_collection.max_dofs_per_line() +
153 16 * dof_handler.fe_collection.max_dofs_per_quad();
154 break;
155
156 // the following numbers are not based on actual counting but by
157 // extrapolating the number sequences from the previous ones (for
158 // example, for n_dofs_per_vertex(), the sequence above is 19, 21,
159 // 28, 30, 37, and is continued as follows):
160 case 9:
161 max_couplings =
162 39 * dof_handler.fe_collection.max_dofs_per_vertex() +
163 59 * dof_handler.fe_collection.max_dofs_per_line() +
164 17 * dof_handler.fe_collection.max_dofs_per_quad();
165 break;
166 case 10:
167 max_couplings =
168 46 * dof_handler.fe_collection.max_dofs_per_vertex() +
169 70 * dof_handler.fe_collection.max_dofs_per_line() +
170 20 * dof_handler.fe_collection.max_dofs_per_quad();
171 break;
172 case 11:
173 max_couplings =
174 48 * dof_handler.fe_collection.max_dofs_per_vertex() +
175 73 * dof_handler.fe_collection.max_dofs_per_line() +
176 21 * dof_handler.fe_collection.max_dofs_per_quad();
177 break;
178 case 12:
179 max_couplings =
180 55 * dof_handler.fe_collection.max_dofs_per_vertex() +
181 84 * dof_handler.fe_collection.max_dofs_per_line() +
182 24 * dof_handler.fe_collection.max_dofs_per_quad();
183 break;
184 case 13:
185 max_couplings =
186 57 * dof_handler.fe_collection.max_dofs_per_vertex() +
187 87 * dof_handler.fe_collection.max_dofs_per_line() +
188 25 * dof_handler.fe_collection.max_dofs_per_quad();
189 break;
190 case 14:
191 max_couplings =
192 63 * dof_handler.fe_collection.max_dofs_per_vertex() +
193 98 * dof_handler.fe_collection.max_dofs_per_line() +
194 28 * dof_handler.fe_collection.max_dofs_per_quad();
195 break;
196 case 15:
197 max_couplings =
198 65 * dof_handler.fe_collection.max_dofs_per_vertex() +
199 103 * dof_handler.fe_collection.max_dofs_per_line() +
200 29 * dof_handler.fe_collection.max_dofs_per_quad();
201 break;
202 case 16:
203 max_couplings =
204 72 * dof_handler.fe_collection.max_dofs_per_vertex() +
205 114 * dof_handler.fe_collection.max_dofs_per_line() +
206 32 * dof_handler.fe_collection.max_dofs_per_quad();
207 break;
208
209 default:
211 max_couplings = 0;
212 }
213 return std::min(max_couplings, dof_handler.n_dofs());
214 }
215
216 template <int spacedim>
217 static unsigned int
219 {
220 // TODO:[?] Invent significantly better estimates than the ones in this
221 // function
222
223 // doing the same thing here is a rather complicated thing, compared
224 // to the 2d case, since it is hard to draw pictures with several
225 // refined hexahedra :-) so I presently only give a coarse
226 // estimate for the case that at most 8 hexes meet at each vertex
227 //
228 // can anyone give better estimate here?
229 const unsigned int max_adjacent_cells =
230 dof_handler.tria->max_adjacent_cells();
231
232 types::global_dof_index max_couplings;
233 if (max_adjacent_cells <= 8)
234 max_couplings =
235 7 * 7 * 7 * dof_handler.fe_collection.max_dofs_per_vertex() +
236 7 * 6 * 7 * 3 * dof_handler.fe_collection.max_dofs_per_line() +
237 9 * 4 * 7 * 3 * dof_handler.fe_collection.max_dofs_per_quad() +
238 27 * dof_handler.fe_collection.max_dofs_per_hex();
239 else
240 {
242 max_couplings = 0;
243 }
244
245 return std::min(max_couplings, dof_handler.n_dofs());
246 }
247
252 template <int dim, int spacedim>
253 static void
255 {
256 dof_handler.object_dof_indices.clear();
257 dof_handler.object_dof_indices.resize(dof_handler.tria->n_levels());
258 dof_handler.object_dof_indices.shrink_to_fit();
259
260 dof_handler.object_dof_ptr.clear();
261 dof_handler.object_dof_ptr.resize(dof_handler.tria->n_levels());
262 dof_handler.object_dof_ptr.shrink_to_fit();
263 }
264
268 template <int dim, int spacedim>
269 static void
271 const unsigned int n_inner_dofs_per_cell)
272 {
273 for (unsigned int i = 0; i < dof_handler.tria->n_levels(); ++i)
274 {
275 dof_handler.object_dof_ptr[i][dim].assign(
276 dof_handler.tria->n_raw_cells(i) + 1, 0);
277
278 for (const auto &cell :
279 dof_handler.tria->cell_iterators_on_level(i))
280 if (cell->is_active() && !cell->is_artificial())
281 dof_handler.object_dof_ptr[i][dim][cell->index() + 1] =
282 n_inner_dofs_per_cell;
283
284 for (unsigned int j = 0; j < dof_handler.tria->n_raw_cells(i); ++j)
285 dof_handler.object_dof_ptr[i][dim][j + 1] +=
286 dof_handler.object_dof_ptr[i][dim][j];
287
288 dof_handler.object_dof_indices[i][dim].resize(
289 dof_handler.object_dof_ptr[i][dim].back(),
291 }
292 }
293
298 template <int dim, int spacedim, typename T>
299 static void
301 const unsigned int structdim,
302 const unsigned int n_raw_entities,
303 const T &cell_process)
304 {
305 if (dof_handler.tria->n_cells() == 0)
306 return;
307
308 dof_handler.object_dof_ptr[0][structdim].assign(n_raw_entities + 1, -1);
309 // determine for each entity the number of dofs
310 for (const auto &cell : dof_handler.tria->cell_iterators())
311 if (cell->is_active() && !cell->is_artificial())
312 cell_process(
313 cell,
314 [&](const unsigned int n_dofs_per_entity,
315 const unsigned int index) {
316 auto &n_dofs_per_entity_target =
317 dof_handler.object_dof_ptr[0][structdim][index + 1];
318
319 // make sure that either the entity has not been visited or
320 // the entity has the same number of dofs assigned
321 Assert((n_dofs_per_entity_target ==
322 static_cast<
324 -1) ||
325 n_dofs_per_entity_target == n_dofs_per_entity),
327
328 n_dofs_per_entity_target = n_dofs_per_entity;
329 });
330
331 // convert the absolute numbers to CRS
332 dof_handler.object_dof_ptr[0][structdim][0] = 0;
333 for (unsigned int i = 1; i < n_raw_entities + 1; ++i)
334 {
335 if (dof_handler.object_dof_ptr[0][structdim][i] ==
336 static_cast<typename DoFHandler<dim, spacedim>::offset_type>(
337 -1))
338 dof_handler.object_dof_ptr[0][structdim][i] =
339 dof_handler.object_dof_ptr[0][structdim][i - 1];
340 else
341 dof_handler.object_dof_ptr[0][structdim][i] +=
342 dof_handler.object_dof_ptr[0][structdim][i - 1];
343 }
344
345 // allocate memory for indices
346 dof_handler.object_dof_indices[0][structdim].resize(
347 dof_handler.object_dof_ptr[0][structdim].back(),
349 }
350
357 template <int dim, int spacedim>
358 static void
360 {
361 reset_to_empty_objects(dof_handler);
362
363 const auto &fe = dof_handler.get_fe();
364
365 // cell
366 reserve_cells(dof_handler,
367 dim == 1 ? fe.n_dofs_per_line() :
368 (dim == 2 ? fe.n_dofs_per_quad(0) :
369 fe.n_dofs_per_hex()));
370
371 // vertices
372 reserve_subentities(dof_handler,
373 0,
374 dof_handler.tria->n_vertices(),
375 [&](const auto &cell, const auto &process) {
376 for (const auto vertex_index :
377 cell->vertex_indices())
378 process(fe.n_dofs_per_vertex(),
379 cell->vertex_index(vertex_index));
380 });
381
382 // lines
383 if (dim == 2 || dim == 3)
384 reserve_subentities(dof_handler,
385 1,
386 dof_handler.tria->n_raw_lines(),
387 [&](const auto &cell, const auto &process) {
388 for (const auto line_index :
389 cell->line_indices())
390 process(fe.n_dofs_per_line(),
391 cell->line(line_index)->index());
392 });
393
394 // quads
395 if (dim == 3)
396 reserve_subentities(dof_handler,
397 2,
398 dof_handler.tria->n_raw_quads(),
399 [&](const auto &cell, const auto &process) {
400 for (const auto face_index :
401 cell->face_indices())
402 process(fe.n_dofs_per_quad(face_index),
403 cell->face(face_index)->index());
404 });
405 }
406
407 template <int spacedim>
408 static void
410 {
411 Assert(dof_handler.get_triangulation().n_levels() > 0,
412 ExcMessage("Invalid triangulation"));
413 dof_handler.clear_mg_space();
414
415 const ::Triangulation<1, spacedim> &tria =
416 dof_handler.get_triangulation();
417 const unsigned int dofs_per_line =
418 dof_handler.get_fe().n_dofs_per_line();
419 const unsigned int n_levels = tria.n_levels();
420
421 for (unsigned int i = 0; i < n_levels; ++i)
422 {
423 dof_handler.mg_levels.emplace_back(
425 dof_handler.mg_levels.back()->dof_object.dofs =
426 std::vector<types::global_dof_index>(tria.n_raw_lines(i) *
427 dofs_per_line,
429 }
430
431 const unsigned int n_vertices = tria.n_vertices();
432
433 dof_handler.mg_vertex_dofs.resize(n_vertices);
434
435 std::vector<unsigned int> max_level(n_vertices, 0);
436 std::vector<unsigned int> min_level(n_vertices, n_levels);
437
438 for (typename ::Triangulation<1, spacedim>::cell_iterator cell =
439 tria.begin();
440 cell != tria.end();
441 ++cell)
442 {
443 const unsigned int level = cell->level();
444
445 for (const auto vertex : cell->vertex_indices())
446 {
447 const unsigned int vertex_index = cell->vertex_index(vertex);
448
449 if (min_level[vertex_index] > level)
450 min_level[vertex_index] = level;
451
452 if (max_level[vertex_index] < level)
453 max_level[vertex_index] = level;
454 }
455 }
456
457 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
458 if (tria.vertex_used(vertex))
459 {
460 Assert(min_level[vertex] < n_levels, ExcInternalError());
461 Assert(max_level[vertex] >= min_level[vertex],
463 dof_handler.mg_vertex_dofs[vertex].init(
464 min_level[vertex],
465 max_level[vertex],
466 dof_handler.get_fe().n_dofs_per_vertex());
467 }
468
469 else
470 {
471 Assert(min_level[vertex] == n_levels, ExcInternalError());
472 Assert(max_level[vertex] == 0, ExcInternalError());
473 dof_handler.mg_vertex_dofs[vertex].init(1, 0, 0);
474 }
475 }
476
477 template <int spacedim>
478 static void
480 {
481 Assert(dof_handler.get_triangulation().n_levels() > 0,
482 ExcMessage("Invalid triangulation"));
483 dof_handler.clear_mg_space();
484
485 const ::FiniteElement<2, spacedim> &fe = dof_handler.get_fe();
486 const ::Triangulation<2, spacedim> &tria =
487 dof_handler.get_triangulation();
488 const unsigned int n_levels = tria.n_levels();
489
490 for (unsigned int i = 0; i < n_levels; ++i)
491 {
492 dof_handler.mg_levels.emplace_back(
493 std::make_unique<
495 dof_handler.mg_levels.back()->dof_object.dofs =
496 std::vector<types::global_dof_index>(
497 tria.n_raw_quads(i) *
498 fe.n_dofs_per_quad(0 /*note: in 2d there is only one quad*/),
500 }
501
502 dof_handler.mg_faces =
503 std::make_unique<internal::DoFHandlerImplementation::DoFFaces<2>>();
504 dof_handler.mg_faces->lines.dofs =
505 std::vector<types::global_dof_index>(tria.n_raw_lines() *
506 fe.n_dofs_per_line(),
508
509 const unsigned int n_vertices = tria.n_vertices();
510
511 dof_handler.mg_vertex_dofs.resize(n_vertices);
512
513 std::vector<unsigned int> max_level(n_vertices, 0);
514 std::vector<unsigned int> min_level(n_vertices, n_levels);
515
516 for (typename ::Triangulation<2, spacedim>::cell_iterator cell =
517 tria.begin();
518 cell != tria.end();
519 ++cell)
520 {
521 const unsigned int level = cell->level();
522
523 for (const auto vertex : cell->vertex_indices())
524 {
525 const unsigned int vertex_index = cell->vertex_index(vertex);
526
527 if (min_level[vertex_index] > level)
528 min_level[vertex_index] = level;
529
530 if (max_level[vertex_index] < level)
531 max_level[vertex_index] = level;
532 }
533 }
534
535 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
536 if (tria.vertex_used(vertex))
537 {
538 Assert(min_level[vertex] < n_levels, ExcInternalError());
539 Assert(max_level[vertex] >= min_level[vertex],
541 dof_handler.mg_vertex_dofs[vertex].init(min_level[vertex],
542 max_level[vertex],
543 fe.n_dofs_per_vertex());
544 }
545
546 else
547 {
548 Assert(min_level[vertex] == n_levels, ExcInternalError());
549 Assert(max_level[vertex] == 0, ExcInternalError());
550 dof_handler.mg_vertex_dofs[vertex].init(1, 0, 0);
551 }
552 }
553
554 template <int spacedim>
555 static void
557 {
558 Assert(dof_handler.get_triangulation().n_levels() > 0,
559 ExcMessage("Invalid triangulation"));
560 dof_handler.clear_mg_space();
561
562 const ::FiniteElement<3, spacedim> &fe = dof_handler.get_fe();
563 const ::Triangulation<3, spacedim> &tria =
564 dof_handler.get_triangulation();
565 const unsigned int n_levels = tria.n_levels();
566
567 for (unsigned int i = 0; i < n_levels; ++i)
568 {
569 dof_handler.mg_levels.emplace_back(
570 std::make_unique<
572 dof_handler.mg_levels.back()->dof_object.dofs =
573 std::vector<types::global_dof_index>(tria.n_raw_hexs(i) *
574 fe.n_dofs_per_hex(),
576 }
577
578 dof_handler.mg_faces =
579 std::make_unique<internal::DoFHandlerImplementation::DoFFaces<3>>();
580 dof_handler.mg_faces->lines.dofs =
581 std::vector<types::global_dof_index>(tria.n_raw_lines() *
582 fe.n_dofs_per_line(),
584
585 // TODO: the implementation makes the assumption that all faces have the
586 // same number of dofs
587 AssertDimension(fe.n_unique_faces(), 1);
588 dof_handler.mg_faces->quads.dofs = std::vector<types::global_dof_index>(
589 tria.n_raw_quads() * fe.n_dofs_per_quad(0 /*=face_no*/),
591
592 const unsigned int n_vertices = tria.n_vertices();
593
594 dof_handler.mg_vertex_dofs.resize(n_vertices);
595
596 std::vector<unsigned int> max_level(n_vertices, 0);
597 std::vector<unsigned int> min_level(n_vertices, n_levels);
598
599 for (typename ::Triangulation<3, spacedim>::cell_iterator cell =
600 tria.begin();
601 cell != tria.end();
602 ++cell)
603 {
604 const unsigned int level = cell->level();
605
606 for (const auto vertex : cell->vertex_indices())
607 {
608 const unsigned int vertex_index = cell->vertex_index(vertex);
609
610 if (min_level[vertex_index] > level)
611 min_level[vertex_index] = level;
612
613 if (max_level[vertex_index] < level)
614 max_level[vertex_index] = level;
615 }
616 }
617
618 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
619 if (tria.vertex_used(vertex))
620 {
621 Assert(min_level[vertex] < n_levels, ExcInternalError());
622 Assert(max_level[vertex] >= min_level[vertex],
624 dof_handler.mg_vertex_dofs[vertex].init(min_level[vertex],
625 max_level[vertex],
626 fe.n_dofs_per_vertex());
627 }
628
629 else
630 {
631 Assert(min_level[vertex] == n_levels, ExcInternalError());
632 Assert(max_level[vertex] == 0, ExcInternalError());
633 dof_handler.mg_vertex_dofs[vertex].init(1, 0, 0);
634 }
635 }
636 };
637 } // namespace DoFHandlerImplementation
638
639
640
641 namespace hp
642 {
643 namespace DoFHandlerImplementation
644 {
650 {
656 template <int dim, int spacedim>
657 static void
659 DoFHandler<dim, spacedim> &dof_handler)
660 {
661 (void)dof_handler;
662 for (const auto &cell : dof_handler.active_cell_iterators())
663 if (cell->is_locally_owned())
664 Assert(
665 !cell->future_fe_index_set(),
667 "There shouldn't be any cells flagged for p-adaptation when partitioning."));
668 }
669
670
671
676 template <int dim, int spacedim>
677 static void
679 {
680 // The final step in all of the reserve_space() functions is to set
681 // up vertex dof information. since vertices are sequentially
682 // numbered, what we do first is to set up an array in which
683 // we record whether a vertex is associated with any of the
684 // given fe's, by setting a bit. in a later step, we then
685 // actually allocate memory for the required dofs
686 //
687 // in the following, we only need to consider vertices that are
688 // adjacent to either a locally owned or a ghost cell; we never
689 // store anything on vertices that are only surrounded by
690 // artificial cells. so figure out that subset of vertices
691 // first
692 std::vector<bool> locally_used_vertices(
693 dof_handler.tria->n_vertices(), false);
694 for (const auto &cell : dof_handler.active_cell_iterators())
695 if (!cell->is_artificial())
696 for (const auto v : cell->vertex_indices())
697 locally_used_vertices[cell->vertex_index(v)] = true;
698
699 std::vector<std::vector<bool>> vertex_fe_association(
700 dof_handler.fe_collection.size(),
701 std::vector<bool>(dof_handler.tria->n_vertices(), false));
702
703 for (const auto &cell : dof_handler.active_cell_iterators())
704 if (!cell->is_artificial())
705 for (const auto v : cell->vertex_indices())
706 vertex_fe_association[cell->active_fe_index()]
707 [cell->vertex_index(v)] = true;
708
709 // in debug mode, make sure that each vertex is associated
710 // with at least one FE (note that except for unused
711 // vertices, all vertices are actually active). this is of
712 // course only true for vertices that are part of either
713 // ghost or locally owned cells
714 if constexpr (running_in_debug_mode())
715 {
716 for (unsigned int v = 0; v < dof_handler.tria->n_vertices(); ++v)
717 if (locally_used_vertices[v] == true)
718 if (dof_handler.tria->vertex_used(v) == true)
719 {
720 unsigned int fe = 0;
721 for (; fe < dof_handler.fe_collection.size(); ++fe)
722 if (vertex_fe_association[fe][v] == true)
723 break;
724 Assert(fe != dof_handler.fe_collection.size(),
726 }
727 }
728
729 const unsigned int d = 0;
730 const unsigned int l = 0;
731
732 dof_handler.hp_object_fe_ptr[d].clear();
733 dof_handler.hp_object_fe_indices[d].clear();
734 dof_handler.object_dof_ptr[l][d].clear();
735 dof_handler.object_dof_indices[l][d].clear();
736
737 dof_handler.hp_object_fe_ptr[d].reserve(
738 dof_handler.tria->n_vertices() + 1);
739
740 unsigned int vertex_slots_needed = 0;
741 unsigned int fe_slots_needed = 0;
742
743 for (unsigned int v = 0; v < dof_handler.tria->n_vertices(); ++v)
744 {
745 dof_handler.hp_object_fe_ptr[d].push_back(fe_slots_needed);
746
747 if (dof_handler.tria->vertex_used(v) && locally_used_vertices[v])
748 {
749 for (unsigned int fe = 0;
750 fe < dof_handler.fe_collection.size();
751 ++fe)
752 if (vertex_fe_association[fe][v] == true)
753 {
754 ++fe_slots_needed;
755 vertex_slots_needed +=
756 dof_handler.get_fe(fe).n_dofs_per_vertex();
757 }
758 }
759 }
760
761 dof_handler.hp_object_fe_ptr[d].push_back(fe_slots_needed);
762
763 dof_handler.hp_object_fe_indices[d].reserve(fe_slots_needed);
764 dof_handler.object_dof_ptr[l][d].reserve(fe_slots_needed + 1);
765
766 dof_handler.object_dof_indices[l][d].reserve(vertex_slots_needed);
767
768 for (unsigned int v = 0; v < dof_handler.tria->n_vertices(); ++v)
769 if (dof_handler.tria->vertex_used(v) && locally_used_vertices[v])
770 {
771 for (unsigned int fe = 0; fe < dof_handler.fe_collection.size();
772 ++fe)
773 if (vertex_fe_association[fe][v] == true)
774 {
775 dof_handler.hp_object_fe_indices[d].push_back(fe);
776 dof_handler.object_dof_ptr[l][d].push_back(
777 dof_handler.object_dof_indices[l][d].size());
778
779 for (unsigned int i = 0;
780 i < dof_handler.get_fe(fe).n_dofs_per_vertex();
781 i++)
782 dof_handler.object_dof_indices[l][d].push_back(
784 }
785 }
786
787
788 dof_handler.object_dof_ptr[l][d].push_back(
789 dof_handler.object_dof_indices[l][d].size());
790
791 AssertDimension(vertex_slots_needed,
792 dof_handler.object_dof_indices[l][d].size());
793 AssertDimension(fe_slots_needed,
794 dof_handler.hp_object_fe_indices[d].size());
795 AssertDimension(fe_slots_needed + 1,
796 dof_handler.object_dof_ptr[l][d].size());
797 AssertDimension(dof_handler.tria->n_vertices() + 1,
798 dof_handler.hp_object_fe_ptr[d].size());
799
800 dof_handler.object_dof_indices[l][d].assign(
801 vertex_slots_needed, numbers::invalid_dof_index);
802 }
803
804
805
810 template <int dim, int spacedim>
811 static void
813 {
814 (void)dof_handler;
815 // count how much space we need on each level for the cell
816 // dofs and set the dof_*_offsets data. initially set the
817 // latter to an invalid index, and only later set it to
818 // something reasonable for active dof_handler.cells
819 //
820 // note that for dof_handler.cells, the situation is simpler
821 // than for other (lower dimensional) objects since exactly
822 // one finite element is used for it
823 for (unsigned int level = 0; level < dof_handler.tria->n_levels();
824 ++level)
825 {
826 dof_handler.object_dof_ptr[level][dim] =
827 std::vector<typename DoFHandler<dim, spacedim>::offset_type>(
828 dof_handler.tria->n_raw_cells(level),
829 static_cast<typename DoFHandler<dim, spacedim>::offset_type>(
830 -1));
831
832 types::global_dof_index next_free_dof = 0;
833 for (auto cell :
834 dof_handler.active_cell_iterators_on_level(level))
835 if (cell->is_active() && !cell->is_artificial())
836 {
837 dof_handler.object_dof_ptr[level][dim][cell->index()] =
838 next_free_dof;
839 next_free_dof +=
840 cell->get_fe().template n_dofs_per_object<dim>();
841 }
842
843 dof_handler.object_dof_indices[level][dim] =
844 std::vector<types::global_dof_index>(
845 next_free_dof, numbers::invalid_dof_index);
846 }
847 }
848
849
850
855 template <int dim, int spacedim>
856 static void
858 {
859 // FACE DOFS
860 //
861 // Count face dofs, then allocate as much space
862 // as we need and prime the linked list for faces (see the
863 // description in hp::DoFLevel) with the indices we will
864 // need. Note that our task is more complicated than for the
865 // cell case above since two adjacent cells may have different
866 // active FE indices, in which case we need to allocate
867 // *two* sets of face dofs for the same face. But they don't
868 // *have* to be different, and so we need to prepare for this
869 // as well.
870 //
871 // The way we do things is that we loop over all active cells (these
872 // are the only ones that have DoFs anyway) and all their faces. We
873 // note in the vector face_touched whether we have previously
874 // visited a face and if so skip it
875 {
876 std::vector<bool> face_touched(dim == 2 ?
877 dof_handler.tria->n_raw_lines() :
878 dof_handler.tria->n_raw_quads());
879
880 const unsigned int d = dim - 1;
881 const unsigned int l = 0;
882
883 dof_handler.hp_object_fe_ptr[d].clear();
884 dof_handler.hp_object_fe_indices[d].clear();
885 dof_handler.object_dof_ptr[l][d].clear();
886 dof_handler.object_dof_indices[l][d].clear();
887
888 dof_handler.hp_object_fe_ptr[d].resize(
889 dof_handler.tria->n_raw_faces() + 1);
890
891 // An array to hold how many slots (see the hp::DoFLevel
892 // class) we will have to store on each level
893 unsigned int n_face_slots = 0;
894
895 for (const auto &cell : dof_handler.active_cell_iterators())
896 if (!cell->is_artificial())
897 for (const auto face : cell->face_indices())
898 if (!face_touched[cell->face(face)->index()])
899 {
900 unsigned int fe_slots_needed = 0;
901
902 if (cell->at_boundary(face) ||
903 cell->face(face)->has_children() ||
904 cell->neighbor_is_coarser(face) ||
905 (!cell->at_boundary(face) &&
906 cell->neighbor(face)->is_artificial()) ||
907 (!cell->at_boundary(face) &&
908 !cell->neighbor(face)->is_artificial() &&
909 (cell->active_fe_index() ==
910 cell->neighbor(face)->active_fe_index())))
911 {
912 fe_slots_needed = 1;
913 n_face_slots +=
914 dof_handler.get_fe(cell->active_fe_index())
915 .template n_dofs_per_object<dim - 1>(face);
916 }
917 else
918 {
919 fe_slots_needed = 2;
920 n_face_slots +=
921 dof_handler.get_fe(cell->active_fe_index())
922 .template n_dofs_per_object<dim - 1>(face) +
923 dof_handler
924 .get_fe(cell->neighbor(face)->active_fe_index())
925 .template n_dofs_per_object<dim - 1>(
926 cell->neighbor_face_no(face));
927 }
928
929 // mark this face as visited
930 face_touched[cell->face(face)->index()] = true;
931
932 dof_handler
933 .hp_object_fe_ptr[d][cell->face(face)->index() + 1] =
934 fe_slots_needed;
935 }
936
937 for (unsigned int i = 1; i < dof_handler.hp_object_fe_ptr[d].size();
938 i++)
939 dof_handler.hp_object_fe_ptr[d][i] +=
940 dof_handler.hp_object_fe_ptr[d][i - 1];
941
942
943 dof_handler.hp_object_fe_indices[d].resize(
944 dof_handler.hp_object_fe_ptr[d].back());
945 dof_handler.object_dof_ptr[l][d].resize(
946 dof_handler.hp_object_fe_ptr[d].back() + 1);
947
948 dof_handler.object_dof_indices[l][d].reserve(n_face_slots);
949
950
951 // With the memory now allocated, loop over the
952 // dof_handler cells again and prime the _offset values as
953 // well as the fe_index fields
954 face_touched = std::vector<bool>(face_touched.size());
955
956 for (const auto &cell : dof_handler.active_cell_iterators())
957 if (!cell->is_artificial())
958 for (const auto face : cell->face_indices())
959 if (!face_touched[cell->face(face)->index()])
960 {
961 // Same decision tree as before
962 if (cell->at_boundary(face) ||
963 cell->face(face)->has_children() ||
964 cell->neighbor_is_coarser(face) ||
965 (!cell->at_boundary(face) &&
966 cell->neighbor(face)->is_artificial()) ||
967 (!cell->at_boundary(face) &&
968 !cell->neighbor(face)->is_artificial() &&
969 (cell->active_fe_index() ==
970 cell->neighbor(face)->active_fe_index())))
971 {
972 const types::fe_index fe = cell->active_fe_index();
973 const unsigned int n_dofs =
974 dof_handler.get_fe(fe)
975 .template n_dofs_per_object<dim - 1>(face);
976 const unsigned int offset =
977 dof_handler
978 .hp_object_fe_ptr[d][cell->face(face)->index()];
979
980 dof_handler.hp_object_fe_indices[d][offset] = fe;
981 dof_handler.object_dof_ptr[l][d][offset + 1] = n_dofs;
982
983 for (unsigned int i = 0; i < n_dofs; ++i)
984 dof_handler.object_dof_indices[l][d].push_back(
986 }
987 else
988 {
989 types::fe_index fe_1 = cell->active_fe_index();
990 unsigned int face_no_1 = face;
991 types::fe_index fe_2 =
992 cell->neighbor(face)->active_fe_index();
993 unsigned int face_no_2 = cell->neighbor_face_no(face);
994
995 if (fe_2 < fe_1)
996 {
997 std::swap(fe_1, fe_2);
998 std::swap(face_no_1, face_no_2);
999 }
1000
1001 const unsigned int n_dofs_1 =
1002 dof_handler.get_fe(fe_1)
1003 .template n_dofs_per_object<dim - 1>(face_no_1);
1004
1005 const unsigned int n_dofs_2 =
1006 dof_handler.get_fe(fe_2)
1007 .template n_dofs_per_object<dim - 1>(face_no_2);
1008
1009 const unsigned int offset =
1010 dof_handler
1011 .hp_object_fe_ptr[d][cell->face(face)->index()];
1012
1013 dof_handler.hp_object_fe_indices[d].push_back(
1014 cell->active_fe_index());
1015 dof_handler.object_dof_ptr[l][d].push_back(
1016 dof_handler.object_dof_indices[l][d].size());
1017
1018 dof_handler.hp_object_fe_indices[d][offset + 0] =
1019 fe_1;
1020 dof_handler.hp_object_fe_indices[d][offset + 1] =
1021 fe_2;
1022 dof_handler.object_dof_ptr[l][d][offset + 1] =
1023 n_dofs_1;
1024 dof_handler.object_dof_ptr[l][d][offset + 2] =
1025 n_dofs_2;
1026
1027
1028 for (unsigned int i = 0; i < n_dofs_1 + n_dofs_2; ++i)
1029 dof_handler.object_dof_indices[l][d].push_back(
1031 }
1032
1033 // mark this face as visited
1034 face_touched[cell->face(face)->index()] = true;
1035 }
1036
1037 for (unsigned int i = 1;
1038 i < dof_handler.object_dof_ptr[l][d].size();
1039 i++)
1040 dof_handler.object_dof_ptr[l][d][i] +=
1041 dof_handler.object_dof_ptr[l][d][i - 1];
1042 }
1043 }
1044
1045
1046
1053 template <int spacedim>
1054 static void
1056 {
1057 Assert(dof_handler.fe_collection.size() > 0,
1059 Assert(dof_handler.tria->n_levels() > 0,
1060 ExcMessage("The current Triangulation must not be empty."));
1061 Assert(dof_handler.tria->n_levels() ==
1062 dof_handler.hp_cell_future_fe_indices.size(),
1064
1066 reset_to_empty_objects(dof_handler);
1067
1069 tasks +=
1072 dof_handler);
1073 tasks.join_all();
1074 }
1075
1076
1077
1078 template <int spacedim>
1079 static void
1081 {
1082 Assert(dof_handler.fe_collection.size() > 0,
1084 Assert(dof_handler.tria->n_levels() > 0,
1085 ExcMessage("The current Triangulation must not be empty."));
1086 Assert(dof_handler.tria->n_levels() ==
1087 dof_handler.hp_cell_future_fe_indices.size(),
1089
1091 reset_to_empty_objects(dof_handler);
1092
1094 tasks +=
1096 tasks +=
1099 dof_handler);
1100 tasks.join_all();
1101 }
1102
1103
1104
1105 template <int spacedim>
1106 static void
1108 {
1109 Assert(dof_handler.fe_collection.size() > 0,
1111 Assert(dof_handler.tria->n_levels() > 0,
1112 ExcMessage("The current Triangulation must not be empty."));
1113 Assert(dof_handler.tria->n_levels() ==
1114 dof_handler.hp_cell_future_fe_indices.size(),
1116
1118 reset_to_empty_objects(dof_handler);
1119
1121 tasks +=
1123 tasks +=
1126 dof_handler);
1127
1128 // While the tasks above are running, we can turn to line dofs
1129
1130 // the situation here is pretty much like with vertices:
1131 // there can be an arbitrary number of finite elements
1132 // associated with each line.
1133 //
1134 // the algorithm we use is somewhat similar to what we do in
1135 // reserve_space_vertices()
1136 {
1137 // what we do first is to set up an array in which we
1138 // record whether a line is associated with any of the
1139 // given fe's, by setting a bit. in a later step, we
1140 // then actually allocate memory for the required dofs
1141 std::vector<std::vector<bool>> line_fe_association(
1142 dof_handler.fe_collection.size(),
1143 std::vector<bool>(dof_handler.tria->n_raw_lines(), false));
1144
1145 for (const auto &cell : dof_handler.active_cell_iterators())
1146 if (!cell->is_artificial())
1147 for (const auto l : cell->line_indices())
1148 line_fe_association[cell->active_fe_index()]
1149 [cell->line_index(l)] = true;
1150
1151 // first check which of the lines is used at all,
1152 // i.e. is associated with a finite element. we do this
1153 // since not all lines may actually be used, in which
1154 // case we do not have to allocate any memory at all
1155 std::vector<bool> line_is_used(dof_handler.tria->n_raw_lines(),
1156 false);
1157 for (unsigned int line = 0; line < dof_handler.tria->n_raw_lines();
1158 ++line)
1159 for (unsigned int fe = 0; fe < dof_handler.fe_collection.size();
1160 ++fe)
1161 if (line_fe_association[fe][line] == true)
1162 {
1163 line_is_used[line] = true;
1164 break;
1165 }
1166
1167
1168
1169 const unsigned int d = 1;
1170 const unsigned int l = 0;
1171
1172 dof_handler.hp_object_fe_ptr[d].clear();
1173 dof_handler.hp_object_fe_indices[d].clear();
1174 dof_handler.object_dof_ptr[l][d].clear();
1175 dof_handler.object_dof_indices[l][d].clear();
1176
1177 dof_handler.hp_object_fe_ptr[d].reserve(
1178 dof_handler.tria->n_raw_lines() + 1);
1179
1180 unsigned int line_slots_needed = 0;
1181 unsigned int fe_slots_needed = 0;
1182
1183 for (unsigned int line = 0; line < dof_handler.tria->n_raw_lines();
1184 ++line)
1185 {
1186 dof_handler.hp_object_fe_ptr[d].push_back(fe_slots_needed);
1187
1188 if (line_is_used[line] == true)
1189 {
1190 for (unsigned int fe = 0;
1191 fe < dof_handler.fe_collection.size();
1192 ++fe)
1193 if (line_fe_association[fe][line] == true)
1194 {
1195 ++fe_slots_needed;
1196 line_slots_needed +=
1197 dof_handler.get_fe(fe).n_dofs_per_line();
1198 }
1199 }
1200 }
1201
1202 dof_handler.hp_object_fe_ptr[d].push_back(fe_slots_needed);
1203
1204 // make sure that all entries have been set
1205 AssertDimension(dof_handler.hp_object_fe_ptr[d].size(),
1206 dof_handler.tria->n_raw_lines() + 1);
1207
1208 dof_handler.hp_object_fe_indices[d].reserve(fe_slots_needed);
1209 dof_handler.object_dof_ptr[l][d].reserve(fe_slots_needed + 1);
1210
1211 dof_handler.object_dof_indices[l][d].reserve(line_slots_needed);
1212
1213 for (unsigned int line = 0; line < dof_handler.tria->n_raw_lines();
1214 ++line)
1215 if (line_is_used[line] == true)
1216 {
1217 for (unsigned int fe = 0;
1218 fe < dof_handler.fe_collection.size();
1219 ++fe)
1220 if (line_fe_association[fe][line] == true)
1221 {
1222 dof_handler.hp_object_fe_indices[d].push_back(fe);
1223 dof_handler.object_dof_ptr[l][d].push_back(
1224 dof_handler.object_dof_indices[l][d].size());
1225
1226 for (unsigned int i = 0;
1227 i < dof_handler.get_fe(fe).n_dofs_per_line();
1228 i++)
1229 dof_handler.object_dof_indices[l][d].push_back(
1231 }
1232 }
1233
1234 dof_handler.object_dof_ptr[l][d].push_back(
1235 dof_handler.object_dof_indices[l][d].size());
1236
1237 // make sure that all entries have been set
1238 AssertDimension(dof_handler.hp_object_fe_indices[d].size(),
1239 fe_slots_needed);
1240 AssertDimension(dof_handler.object_dof_ptr[l][d].size(),
1241 fe_slots_needed + 1);
1242 AssertDimension(dof_handler.object_dof_indices[l][d].size(),
1243 line_slots_needed);
1244 }
1245
1246 // Ensure that everything is done at this point.
1247 tasks.join_all();
1248 }
1249
1250
1251
1263 template <int dim, int spacedim>
1264 static void
1266 {
1267 Assert(
1268 dof_handler.hp_capability_enabled == true,
1270
1271 if (const ::parallel::shared::Triangulation<dim, spacedim> *tr =
1272 dynamic_cast<
1273 const ::parallel::shared::Triangulation<dim, spacedim>
1274 *>(&dof_handler.get_triangulation()))
1275 {
1276 // we have a shared triangulation. in this case, every processor
1277 // knows about all cells, but every processor only has knowledge
1278 // about the active FE index on the cells it owns.
1279 //
1280 // we can create a complete set of active FE indices by letting
1281 // every processor create a vector of indices for all cells,
1282 // filling only those on the cells it owns and setting the indices
1283 // on the other cells to zero. then we add all of these vectors
1284 // up, and because every vector entry has exactly one processor
1285 // that owns it, the sum is correct
1286 std::vector<types::fe_index> active_fe_indices(
1287 tr->n_active_cells(), 0u);
1288 for (const auto &cell : dof_handler.active_cell_iterators())
1289 if (cell->is_locally_owned())
1290 active_fe_indices[cell->active_cell_index()] =
1291 cell->active_fe_index();
1292
1293 Utilities::MPI::sum(active_fe_indices,
1294 tr->get_mpi_communicator(),
1295 active_fe_indices);
1296
1297 // now go back and fill the active FE index on all other
1298 // cells. we would like to call cell->set_active_fe_index(),
1299 // but that function does not allow setting these indices on
1300 // non-locally_owned cells. so we have to work around the
1301 // issue a little bit by accessing the underlying data
1302 // structures directly
1303 for (const auto &cell : dof_handler.active_cell_iterators())
1304 if (!cell->is_locally_owned())
1305 dof_handler
1306 .hp_cell_active_fe_indices[cell->level()][cell->index()] =
1307 active_fe_indices[cell->active_cell_index()];
1308 }
1309 else if (const ::parallel::
1310 DistributedTriangulationBase<dim, spacedim> *tr =
1311 dynamic_cast<
1312 const ::parallel::
1313 DistributedTriangulationBase<dim, spacedim> *>(
1314 &dof_handler.get_triangulation()))
1315 {
1316 // For completely distributed meshes, use the function that is
1317 // able to move data from locally owned cells on one processor to
1318 // the corresponding ghost cells on others. To this end, we need
1319 // to have functions that can pack and unpack the data we want to
1320 // transport -- namely, the single unsigned int active_fe_index
1321 // objects
1322 auto pack =
1323 [](
1325 &cell) -> types::fe_index {
1326 return cell->active_fe_index();
1327 };
1328
1329 auto unpack =
1330 [&dof_handler](
1332 &cell,
1333 const types::fe_index active_fe_index) -> void {
1334 // we would like to say
1335 // cell->set_active_fe_index(active_fe_index);
1336 // but this is not allowed on cells that are not
1337 // locally owned, and we are on a ghost cell
1338 dof_handler
1339 .hp_cell_active_fe_indices[cell->level()][cell->index()] =
1340 active_fe_index;
1341 };
1342
1345 DoFHandler<dim, spacedim>>(dof_handler, pack, unpack);
1346 }
1347 else
1348 {
1349 // a sequential triangulation. there is nothing we need to do here
1350 Assert(
1351 (dynamic_cast<
1352 const ::parallel::TriangulationBase<dim, spacedim> *>(
1353 &dof_handler.get_triangulation()) == nullptr),
1355 }
1356 }
1357
1358
1359
1373 template <int dim, int spacedim>
1374 static void
1376 {
1377 Assert(
1378 dof_handler.hp_capability_enabled == true,
1380
1381 if (const ::parallel::shared::Triangulation<dim, spacedim> *tr =
1382 dynamic_cast<
1383 const ::parallel::shared::Triangulation<dim, spacedim>
1384 *>(&dof_handler.get_triangulation()))
1385 {
1386 std::vector<types::fe_index> future_fe_indices(
1387 tr->n_active_cells(), 0u);
1388 for (const auto &cell : dof_handler.active_cell_iterators() |
1390 future_fe_indices[cell->active_cell_index()] =
1391 dof_handler
1392 .hp_cell_future_fe_indices[cell->level()][cell->index()];
1393
1394 Utilities::MPI::sum(future_fe_indices,
1395 tr->get_mpi_communicator(),
1396 future_fe_indices);
1397
1398 for (const auto &cell : dof_handler.active_cell_iterators())
1399 if (!cell->is_locally_owned())
1400 dof_handler
1401 .hp_cell_future_fe_indices[cell->level()][cell->index()] =
1402 future_fe_indices[cell->active_cell_index()];
1403 }
1404 else if (const ::parallel::
1405 DistributedTriangulationBase<dim, spacedim> *tr =
1406 dynamic_cast<
1407 const ::parallel::
1408 DistributedTriangulationBase<dim, spacedim> *>(
1409 &dof_handler.get_triangulation()))
1410 {
1411 auto pack =
1412 [&dof_handler](
1414 &cell) -> types::fe_index {
1415 return dof_handler
1416 .hp_cell_future_fe_indices[cell->level()][cell->index()];
1417 };
1418
1419 auto unpack =
1420 [&dof_handler](
1422 &cell,
1423 const types::fe_index future_fe_index) -> void {
1424 dof_handler
1425 .hp_cell_future_fe_indices[cell->level()][cell->index()] =
1426 future_fe_index;
1427 };
1428
1431 DoFHandler<dim, spacedim>>(dof_handler, pack, unpack);
1432 }
1433 else
1434 {
1435 Assert(
1436 (dynamic_cast<
1437 const ::parallel::TriangulationBase<dim, spacedim> *>(
1438 &dof_handler.get_triangulation()) == nullptr),
1440 }
1441 }
1442
1443
1444
1465 template <int dim, int spacedim>
1466 static void
1468 DoFHandler<dim, spacedim> &dof_handler)
1469 {
1470 const auto &fe_transfer = dof_handler.active_fe_index_transfer;
1471
1472 for (const auto &cell : dof_handler.active_cell_iterators())
1473 if (cell->is_locally_owned())
1474 {
1475 if (cell->refine_flag_set())
1476 {
1477 // Store the active FE index of each cell that will be
1478 // refined to and distribute it later on its children.
1479 // Pick their future index if flagged for p-refinement.
1480 fe_transfer->refined_cells_fe_index.emplace_back(
1481 cell, cell->future_fe_index());
1482 }
1483 else if (cell->coarsen_flag_set())
1484 {
1485 // From all cells that will be coarsened, determine their
1486 // parent and calculate its proper active FE index, so that
1487 // it can be set after refinement. But first, check if that
1488 // particular cell has a parent at all.
1489 Assert(cell->level() > 0, ExcInternalError());
1490 const auto &parent = cell->parent();
1491
1492 // Check if the active FE index for the current cell has
1493 // been determined already.
1494 if (fe_transfer->coarsened_cells_fe_index.find(parent) ==
1495 fe_transfer->coarsened_cells_fe_index.end())
1496 {
1497 // Find a suitable active FE index for the parent cell
1498 // based on the 'least dominant finite element' of its
1499 // children. Consider the childrens' hypothetical future
1500 // index when they have been flagged for p-refinement.
1501 if constexpr (library_build_mode ==
1503 {
1504 for (const auto &child : parent->child_iterators())
1505 Assert(child->is_active() &&
1506 child->coarsen_flag_set(),
1509 }
1510
1511 const types::fe_index fe_index = ::internal::hp::
1514 parent);
1515
1516 fe_transfer->coarsened_cells_fe_index.insert(
1517 {parent, fe_index});
1518 }
1519 }
1520 else
1521 {
1522 // No h-refinement is scheduled for this cell.
1523 // However, it may have p-refinement indicators, so we
1524 // choose a new active FE index based on its flags.
1525 if (cell->future_fe_index_set() == true)
1526 fe_transfer->persisting_cells_fe_index.emplace_back(
1527 cell, cell->future_fe_index());
1528 }
1529 }
1530 }
1531
1532
1533
1538 template <int dim, int spacedim>
1539 static void
1541 DoFHandler<dim, spacedim> &dof_handler)
1542 {
1543 const auto &fe_transfer = dof_handler.active_fe_index_transfer;
1544
1545 // Set active FE indices on persisting cells.
1546 for (const auto &persist : fe_transfer->persisting_cells_fe_index)
1547 {
1548 const auto &cell = persist.first;
1549
1550 if (cell->is_locally_owned())
1551 {
1552 Assert(cell->is_active(), ExcInternalError());
1553 cell->set_active_fe_index(persist.second);
1554 }
1555 }
1556
1557 // Distribute active FE indices from all refined cells on their
1558 // respective children.
1559 for (const auto &refine : fe_transfer->refined_cells_fe_index)
1560 {
1561 const auto &parent = refine.first;
1562
1563 for (const auto &child : parent->child_iterators())
1564 if (child->is_locally_owned())
1565 {
1566 Assert(child->is_active(), ExcInternalError());
1567 child->set_active_fe_index(refine.second);
1568 }
1569 }
1570
1571 // Set active FE indices on coarsened cells that have been determined
1572 // before the actual coarsening happened.
1573 for (const auto &coarsen : fe_transfer->coarsened_cells_fe_index)
1574 {
1575 const auto &cell = coarsen.first;
1576
1577 if (cell->is_locally_owned())
1578 {
1579 Assert(cell->is_active(), ExcInternalError());
1580 cell->set_active_fe_index(coarsen.second);
1581 }
1582 }
1583 }
1584
1585
1596 template <int dim, int spacedim>
1597 static types::fe_index
1600 const std::vector<types::fe_index> &children_fe_indices,
1601 const ::hp::FECollection<dim, spacedim> &fe_collection)
1602 {
1603 Assert(!children_fe_indices.empty(), ExcInternalError());
1604
1605 // convert vector to set
1606 // TODO: Change set to types::fe_index
1607 const std::set<unsigned int> children_fe_indices_set(
1608 children_fe_indices.begin(), children_fe_indices.end());
1609
1610 const types::fe_index dominated_fe_index =
1611 fe_collection.find_dominated_fe_extended(children_fe_indices_set,
1612 /*codim=*/0);
1613
1614 Assert(dominated_fe_index != numbers::invalid_fe_index,
1616
1617 return dominated_fe_index;
1618 }
1619
1620
1628 template <int dim, int spacedim>
1629 static types::fe_index
1631 const typename DoFHandler<dim, spacedim>::cell_iterator &parent)
1632 {
1633 Assert(
1634 !parent->is_active(),
1635 ExcMessage(
1636 "You ask for information on children of this cell which is only "
1637 "available for active cells. This cell has no children."));
1638
1639 const auto &dof_handler = parent->get_dof_handler();
1640 Assert(
1641 dof_handler.has_hp_capabilities(),
1643
1644 // TODO: Change set to types::fe_index
1645 std::set<unsigned int> future_fe_indices_children;
1646 for (const auto &child : parent->child_iterators())
1647 {
1648 Assert(
1649 child->is_active(),
1650 ExcMessage(
1651 "You ask for information on children of this cell which is only "
1652 "available for active cells. One of its children is not active."));
1653
1654 // Ghost siblings might occur on parallel Triangulation
1655 // objects. The public interface does not allow to access future
1656 // FE indices on ghost cells. However, we need this information
1657 // here and thus call the internal function that does not check
1658 // for cell ownership. This requires that future FE indices have
1659 // been communicated prior to calling this function.
1660 const types::fe_index future_fe_index_child =
1663
1664 future_fe_indices_children.insert(future_fe_index_child);
1665 }
1666 Assert(!future_fe_indices_children.empty(), ExcInternalError());
1667
1668 const types::fe_index future_fe_index =
1669 dof_handler.fe_collection.find_dominated_fe_extended(
1670 future_fe_indices_children,
1671 /*codim=*/0);
1672
1673 Assert(future_fe_index != numbers::invalid_fe_index,
1675
1676 return future_fe_index;
1677 }
1678 };
1679
1680
1681
1685 template <int dim, int spacedim>
1686 void
1692
1693
1694
1698 template <int dim, int spacedim>
1699 unsigned int
1706 } // namespace DoFHandlerImplementation
1707 } // namespace hp
1708} // namespace internal
1709
1710#ifndef DOXYGEN
1711
1712template <int dim, int spacedim>
1715 : hp_capability_enabled(true)
1716 , tria(nullptr, typeid(*this).name())
1717 , mg_faces(nullptr)
1718{}
1719
1720
1721
1722template <int dim, int spacedim>
1723DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1724DoFHandler<dim, spacedim>::DoFHandler(const Triangulation<dim, spacedim> &tria)
1725 : DoFHandler()
1726{
1727 reinit(tria);
1728}
1729
1730
1731
1732template <int dim, int spacedim>
1733DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1735{
1736 // unsubscribe all attachments to signals of the underlying triangulation
1737 for (auto &connection : this->tria_listeners)
1738 connection.disconnect();
1739 this->tria_listeners.clear();
1740
1741 for (auto &connection : this->tria_listeners_for_transfer)
1742 connection.disconnect();
1743 this->tria_listeners_for_transfer.clear();
1744
1745 // release allocated memory
1746 // virtual functions called in constructors and destructors never use the
1747 // override in a derived class
1748 // for clarity be explicit on which function is called
1750
1751 // also release the policy. this needs to happen before the
1752 // current object disappears because the policy objects
1753 // store references to the DoFhandler object they work on
1754 this->policy.reset();
1755}
1756
1757
1758
1759template <int dim, int spacedim>
1760DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1761void DoFHandler<dim, spacedim>::reinit(const Triangulation<dim, spacedim> &tria)
1762{
1763 //
1764 // call destructor
1765 //
1766 // remove association with old triangulation
1767 for (auto &connection : this->tria_listeners)
1768 connection.disconnect();
1769 this->tria_listeners.clear();
1770
1771 for (auto &connection : this->tria_listeners_for_transfer)
1772 connection.disconnect();
1773 this->tria_listeners_for_transfer.clear();
1774
1775 // release allocated memory and policy
1777 this->policy.reset();
1778
1779 // reset the finite element collection
1780 this->fe_collection = hp::FECollection<dim, spacedim>();
1781
1782 //
1783 // call constructor
1784 //
1785 // establish connection to new triangulation
1786 this->tria = &tria;
1787 this->setup_policy();
1788
1789 // start in hp-mode and let distribute_dofs toggle it if necessary
1790 hp_capability_enabled = true;
1791 this->connect_to_triangulation_signals();
1792 this->create_active_fe_table();
1793}
1794
1795#endif
1796/*------------------------ Cell iterator functions ------------------------*/
1797#ifndef DOXYGEN
1798template <int dim, int spacedim>
1799DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1801 DoFHandler<dim, spacedim>::begin(const unsigned int level) const
1802{
1804 this->get_triangulation().begin(level);
1805 if (cell == this->get_triangulation().end(level))
1806 return end(level);
1807 return cell_iterator(*cell, this);
1808}
1809
1810
1811
1812template <int dim, int spacedim>
1813DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1815 DoFHandler<dim, spacedim>::begin_active(const unsigned int level) const
1816{
1817 // level is checked in begin
1818 cell_iterator i = begin(level);
1819 if (i.state() != IteratorState::valid)
1820 return i;
1821 while (i->has_children())
1822 if ((++i).state() != IteratorState::valid)
1823 return i;
1824 return i;
1825}
1826
1827
1828
1829template <int dim, int spacedim>
1830DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1833{
1834 return cell_iterator(&this->get_triangulation(), -1, -1, this);
1835}
1836
1837
1838
1839template <int dim, int spacedim>
1840DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1842 DoFHandler<dim, spacedim>::end(const unsigned int level) const
1843{
1845 this->get_triangulation().end(level);
1846 if (cell.state() != IteratorState::valid)
1847 return end();
1848 return cell_iterator(*cell, this);
1849}
1850
1851
1852
1853template <int dim, int spacedim>
1854DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1856 DoFHandler<dim, spacedim>::end_active(const unsigned int level) const
1857{
1859 this->get_triangulation().end_active(level);
1860 if (cell.state() != IteratorState::valid)
1861 return active_cell_iterator(end());
1862 return active_cell_iterator(*cell, this);
1863}
1864
1865
1866
1867template <int dim, int spacedim>
1868DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1870 DoFHandler<dim, spacedim>::begin_mg(const unsigned int level) const
1871{
1872 Assert(this->has_level_dofs(),
1873 ExcMessage("You can only iterate over mg "
1874 "levels if mg dofs got distributed."));
1876 this->get_triangulation().begin(level);
1877 if (cell == this->get_triangulation().end(level))
1878 return end_mg(level);
1879 return level_cell_iterator(*cell, this);
1880}
1881
1882
1883
1884template <int dim, int spacedim>
1885DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1887 DoFHandler<dim, spacedim>::end_mg(const unsigned int level) const
1888{
1889 Assert(this->has_level_dofs(),
1890 ExcMessage("You can only iterate over mg "
1891 "levels if mg dofs got distributed."));
1893 this->get_triangulation().end(level);
1894 if (cell.state() != IteratorState::valid)
1895 return end();
1896 return level_cell_iterator(*cell, this);
1897}
1898
1899
1900
1901template <int dim, int spacedim>
1902DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1905{
1906 return level_cell_iterator(&this->get_triangulation(), -1, -1, this);
1907}
1908
1909
1910
1911template <int dim, int spacedim>
1912DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1913IteratorRange<typename DoFHandler<dim, spacedim>::cell_iterator> DoFHandler<
1914 dim,
1915 spacedim>::cell_iterators() const
1916{
1917 return IteratorRange<typename DoFHandler<dim, spacedim>::cell_iterator>(
1918 begin(), end());
1919}
1920
1921
1922
1923template <int dim, int spacedim>
1924DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1925IteratorRange<typename DoFHandler<dim, spacedim>::
1926 active_cell_iterator> DoFHandler<dim, spacedim>::
1928{
1929 return IteratorRange<
1930 typename DoFHandler<dim, spacedim>::active_cell_iterator>(begin_active(),
1931 end());
1932}
1933
1934
1935
1936template <int dim, int spacedim>
1937DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1938IteratorRange<
1939 typename DoFHandler<dim, spacedim>::
1940 level_cell_iterator> DoFHandler<dim, spacedim>::mg_cell_iterators() const
1941{
1942 return IteratorRange<typename DoFHandler<dim, spacedim>::level_cell_iterator>(
1943 begin_mg(), end_mg());
1944}
1945
1946
1947
1948template <int dim, int spacedim>
1949DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1950IteratorRange<typename DoFHandler<dim, spacedim>::cell_iterator> DoFHandler<
1951 dim,
1952 spacedim>::cell_iterators_on_level(const unsigned int level) const
1953{
1954 return IteratorRange<typename DoFHandler<dim, spacedim>::cell_iterator>(
1955 begin(level), end(level));
1956}
1957
1958
1959
1960template <int dim, int spacedim>
1961DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1962IteratorRange<typename DoFHandler<dim, spacedim>::
1963 active_cell_iterator> DoFHandler<dim, spacedim>::
1964 active_cell_iterators_on_level(const unsigned int level) const
1965{
1966 return IteratorRange<
1968 begin_active(level), end_active(level));
1969}
1970
1971
1972
1973template <int dim, int spacedim>
1974DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1975IteratorRange<typename DoFHandler<dim, spacedim>::
1976 level_cell_iterator> DoFHandler<dim, spacedim>::
1977 mg_cell_iterators_on_level(const unsigned int level) const
1978{
1979 return IteratorRange<typename DoFHandler<dim, spacedim>::level_cell_iterator>(
1980 begin_mg(level), end_mg(level));
1981}
1982
1983
1984
1985//---------------------------------------------------------------------------
1986
1987
1988
1989template <int dim, int spacedim>
1990DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
1992{
1993 Assert(!(dim == 2 && spacedim == 3) || hp_capability_enabled == false,
1994 ExcNotImplementedWithHP());
1995
1996 Assert(this->fe_collection.size() > 0, ExcNoFESelected());
1997
1998 std::unordered_set<types::global_dof_index> boundary_dofs;
1999 std::vector<types::global_dof_index> dofs_on_face;
2000 dofs_on_face.reserve(this->get_fe_collection().max_dofs_per_face());
2001
2002 const IndexSet &owned_dofs = locally_owned_dofs();
2003
2004 // loop over all faces to check whether they are at a
2005 // boundary. note that we need not take special care of single
2006 // lines in 3d (using @p{cell->has_boundary_lines}), since we do
2007 // not support boundaries of dimension dim-2, and so every
2008 // boundary line is also part of a boundary face.
2009 for (const auto &cell : this->active_cell_iterators())
2010 if (cell->is_locally_owned() && cell->at_boundary())
2011 {
2012 for (const auto iface : cell->face_indices())
2013 {
2014 const auto face = cell->face(iface);
2015 if (face->at_boundary())
2016 {
2017 const unsigned int dofs_per_face =
2018 cell->get_fe().n_dofs_per_face(iface);
2019 dofs_on_face.resize(dofs_per_face);
2020
2021 face->get_dof_indices(dofs_on_face, cell->active_fe_index());
2022 for (unsigned int i = 0; i < dofs_per_face; ++i)
2023 {
2024 const unsigned int global_idof_index = dofs_on_face[i];
2025 if (owned_dofs.is_element(global_idof_index))
2026 {
2027 boundary_dofs.insert(global_idof_index);
2028 }
2029 }
2030 }
2031 }
2032 }
2033 return boundary_dofs.size();
2034}
2035
2036
2037
2038template <int dim, int spacedim>
2039DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2041 const std::set<types::boundary_id> &boundary_ids) const
2042{
2043 Assert(!(dim == 2 && spacedim == 3) || hp_capability_enabled == false,
2044 ExcNotImplementedWithHP());
2045
2046 Assert(this->fe_collection.size() > 0, ExcNoFESelected());
2047 Assert(boundary_ids.find(numbers::internal_face_boundary_id) ==
2048 boundary_ids.end(),
2049 ExcInvalidBoundaryIndicator());
2050
2051 // same as above, but with additional checks for set of boundary
2052 // indicators
2053 std::unordered_set<types::global_dof_index> boundary_dofs;
2054 std::vector<types::global_dof_index> dofs_on_face;
2055 dofs_on_face.reserve(this->get_fe_collection().max_dofs_per_face());
2056
2057 const IndexSet &owned_dofs = locally_owned_dofs();
2058
2059 for (const auto &cell : this->active_cell_iterators())
2060 if (cell->is_locally_owned() && cell->at_boundary())
2061 {
2062 for (const auto iface : cell->face_indices())
2063 {
2064 const auto face = cell->face(iface);
2065 const unsigned int boundary_id = face->boundary_id();
2066 if (face->at_boundary() &&
2067 (boundary_ids.find(boundary_id) != boundary_ids.end()))
2068 {
2069 const unsigned int dofs_per_face =
2070 cell->get_fe().n_dofs_per_face(iface);
2071 dofs_on_face.resize(dofs_per_face);
2072
2073 face->get_dof_indices(dofs_on_face, cell->active_fe_index());
2074 for (unsigned int i = 0; i < dofs_per_face; ++i)
2075 {
2076 const unsigned int global_idof_index = dofs_on_face[i];
2077 if (owned_dofs.is_element(global_idof_index))
2078 {
2079 boundary_dofs.insert(global_idof_index);
2080 }
2081 }
2082 }
2083 }
2084 }
2085 return boundary_dofs.size();
2086}
2087
2088
2089
2090template <int dim, int spacedim>
2091DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2093{
2094 std::size_t mem = MemoryConsumption::memory_consumption(this->tria) +
2095 MemoryConsumption::memory_consumption(this->fe_collection) +
2096 MemoryConsumption::memory_consumption(this->number_cache);
2097
2098 mem += MemoryConsumption::memory_consumption(object_dof_indices) +
2100 MemoryConsumption::memory_consumption(hp_object_fe_indices) +
2101 MemoryConsumption::memory_consumption(hp_object_fe_ptr) +
2102 MemoryConsumption::memory_consumption(hp_cell_active_fe_indices) +
2103 MemoryConsumption::memory_consumption(hp_cell_future_fe_indices);
2104
2105
2106 if (hp_capability_enabled)
2107 {
2108 // nothing to add
2109 }
2110 else
2111 {
2112 // collect size of multigrid data structures
2113
2114 mem += MemoryConsumption::memory_consumption(this->block_info_object);
2115
2116 for (unsigned int level = 0; level < this->mg_levels.size(); ++level)
2117 mem += this->mg_levels[level]->memory_consumption();
2118
2119 if (this->mg_faces != nullptr)
2120 mem += MemoryConsumption::memory_consumption(*this->mg_faces);
2121
2122 for (unsigned int i = 0; i < this->mg_vertex_dofs.size(); ++i)
2123 mem += sizeof(MGVertexDoFs) +
2124 (1 + this->mg_vertex_dofs[i].get_finest_level() -
2125 this->mg_vertex_dofs[i].get_coarsest_level()) *
2127 }
2128
2129 return mem;
2130}
2131
2132
2133
2134template <int dim, int spacedim>
2135DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2137 const FiniteElement<dim, spacedim> &fe)
2138{
2139 this->distribute_dofs(hp::FECollection<dim, spacedim>(fe));
2140}
2141
2142
2143
2144template <int dim, int spacedim>
2145DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2147 const hp::FECollection<dim, spacedim> &ff)
2148{
2149 Assert(this->tria != nullptr,
2150 ExcMessage(
2151 "You need to set the Triangulation in the DoFHandler using reinit() "
2152 "or in the constructor before you can distribute DoFs."));
2153 Assert(this->tria->n_levels() > 0,
2154 ExcMessage("The Triangulation you are using is empty!"));
2155
2156 // verify size of provided FE collection
2157 Assert(ff.size() > 0, ExcMessage("The given hp::FECollection is empty!"));
2158 Assert((ff.size() <= std::numeric_limits<types::fe_index>::max()) &&
2160 ExcMessage("The given hp::FECollection contains more finite elements "
2161 "than the DoFHandler can cover with active FE indices."));
2162
2163 if constexpr (running_in_debug_mode())
2164 {
2165 // make sure that the provided FE collection is large enough to
2166 // cover all FE indices presently in use on the mesh
2167 if ((hp_cell_active_fe_indices.size() > 0) &&
2168 (hp_cell_future_fe_indices.size() > 0))
2169 {
2170 Assert(hp_capability_enabled, ExcInternalError());
2171
2172 for (const auto &cell : this->active_cell_iterators() |
2173 IteratorFilters::LocallyOwnedCell())
2174 {
2175 Assert(cell->active_fe_index() < ff.size(),
2176 ExcInvalidFEIndex(cell->active_fe_index(), ff.size()));
2177 Assert(cell->future_fe_index() < ff.size(),
2178 ExcInvalidFEIndex(cell->future_fe_index(), ff.size()));
2179 }
2180 }
2181 }
2182
2183 //
2184 // register the new finite element collection
2185 //
2186 // don't create a new object if the one we have is identical
2187 if (this->fe_collection != ff)
2188 {
2189 this->fe_collection = hp::FECollection<dim, spacedim>(ff);
2190
2191 const bool contains_multiple_fes = (this->fe_collection.size() > 1);
2192
2193 // disable hp-mode if only a single finite element has been registered
2194 if (hp_capability_enabled && !contains_multiple_fes)
2195 {
2196 hp_capability_enabled = false;
2197
2198 // unsubscribe connections to signals that are only relevant for
2199 // hp-mode, since we only have a single element here
2200 for (auto &connection : this->tria_listeners_for_transfer)
2201 connection.disconnect();
2202 this->tria_listeners_for_transfer.clear();
2203
2204 // release active and future finite element tables
2205 this->hp_cell_active_fe_indices.clear();
2206 this->hp_cell_active_fe_indices.shrink_to_fit();
2207 this->hp_cell_future_fe_indices.clear();
2208 this->hp_cell_future_fe_indices.shrink_to_fit();
2209 }
2210
2211 // re-enabling hp-mode is not permitted since the active and future FE
2212 // tables are no longer available
2214 hp_capability_enabled || !contains_multiple_fes,
2215 ExcMessage(
2216 "You cannot re-enable hp-capabilities after you registered a single "
2217 "finite element. Please call reinit() or create a new DoFHandler "
2218 "object instead."));
2219 }
2220
2221 //
2222 // enumerate all degrees of freedom
2223 //
2224 if (hp_capability_enabled)
2225 {
2226 // make sure every processor knows the active FE indices
2227 // on both its own cells and all ghost cells
2230 }
2231
2232 {
2233 // We would like to enumerate all dofs for shared::Triangulations. If an
2234 // underlying shared::Tria allows artificial cells, we need to restore the
2235 // true cell owners temporarily.
2236 // We use the TemporarilyRestoreSubdomainIds class for this purpose: we save
2237 // the current set of subdomain ids, set subdomain ids to the "true" owner
2238 // of each cell upon construction of the TemporarilyRestoreSubdomainIds
2239 // object, and later restore these flags when it is destroyed.
2240 const internal::parallel::shared::TemporarilyRestoreSubdomainIds<dim,
2241 spacedim>
2242 subdomain_modifier(this->get_triangulation());
2243
2244 // Adjust size of levels to the triangulation. Note that we still have to
2245 // allocate space for all degrees of freedom on this mesh (including ghost
2246 // and cells that are entirely stored on different processors), though we
2247 // may not assign numbers to some of them (i.e. they will remain at
2248 // invalid_dof_index). We need to allocate the space because we will want
2249 // to be able to query the dof_indices on each cell, and simply be told
2250 // that we don't know them on some cell (i.e. get back invalid_dof_index)
2251 if (hp_capability_enabled)
2253 *this);
2254 else
2256 }
2257
2258 // hand the actual work over to the policy
2259 this->number_cache = this->policy->distribute_dofs();
2260
2261 // do some housekeeping: compress indices
2262 // if(hp_capability_enabled)
2263 // {
2264 // Threads::TaskGroup<> tg;
2265 // for (int level = this->levels_hp.size() - 1; level >= 0; --level)
2266 // tg += Threads::new_task(
2267 // &::internal::hp::DoFLevel::compress_data<dim, spacedim>,
2268 // *this->levels_hp[level],
2269 // this->fe_collection);
2270 // tg.join_all();
2271 // }
2272
2273 // Initialize the block info object only if this is a sequential
2274 // triangulation. It doesn't work correctly yet if it is parallel and has not
2275 // yet been implemented for hp-mode.
2276 if (!hp_capability_enabled &&
2277 dynamic_cast<const parallel::DistributedTriangulationBase<dim, spacedim>
2278 *>(&*this->tria) == nullptr)
2279 this->block_info_object.initialize(*this, false, true);
2280}
2281
2282
2283
2284template <int dim, int spacedim>
2285DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2287{
2288 AssertThrow(hp_capability_enabled == false, ExcNotImplementedWithHP());
2289
2290 Assert(
2291 this->object_dof_indices.size() > 0,
2292 ExcMessage(
2293 "Distribute active DoFs using distribute_dofs() before calling distribute_mg_dofs()."));
2294
2295 Assert(
2296 ((this->tria->get_mesh_smoothing() &
2299 ExcMessage(
2300 "The mesh smoothing requirement 'limit_level_difference_at_vertices' has to be set for using multigrid!"));
2301
2302 this->clear_mg_space();
2303
2305 this->mg_number_cache = this->policy->distribute_mg_dofs();
2306
2307 // initialize the block info object only if this is a sequential
2308 // triangulation. it doesn't work correctly yet if it is parallel
2309 if (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
2310 &*this->tria) == nullptr)
2311 this->block_info_object.initialize(*this, true, false);
2312}
2313
2314
2315
2316template <int dim, int spacedim>
2317DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2319{
2320 AssertThrow(hp_capability_enabled == false, ExcNotImplementedWithHP());
2321
2322 this->block_info_object.initialize_local(*this);
2323}
2324
2325
2326
2327template <int dim, int spacedim>
2328DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2330{
2331 // decide whether we need a sequential or a parallel distributed policy
2332 if (dynamic_cast<const ::parallel::shared::Triangulation<dim, spacedim>
2333 *>(&this->get_triangulation()) != nullptr)
2334 this->policy = std::make_unique<internal::DoFHandlerImplementation::Policy::
2335 ParallelShared<dim, spacedim>>(*this);
2336 else if (dynamic_cast<
2337 const ::parallel::DistributedTriangulationBase<dim, spacedim>
2338 *>(&this->get_triangulation()) == nullptr)
2339 this->policy = std::make_unique<
2340 internal::DoFHandlerImplementation::Policy::Sequential<dim, spacedim>>(
2341 *this);
2342 else
2343 this->policy =
2344 std::make_unique<internal::DoFHandlerImplementation::Policy::
2345 ParallelDistributed<dim, spacedim>>(*this);
2346}
2347
2348
2349
2350template <int dim, int spacedim>
2351DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2353{
2354 // release memory
2355 this->clear_space();
2356 this->clear_mg_space();
2357}
2358
2359
2360
2361template <int dim, int spacedim>
2362DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2364{
2365 object_dof_indices.clear();
2366
2367 object_dof_ptr.clear();
2368
2369 this->number_cache.clear();
2370
2371 this->hp_cell_active_fe_indices.clear();
2372 this->hp_cell_future_fe_indices.clear();
2373}
2374
2375
2376
2377template <int dim, int spacedim>
2378DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2380{
2381 this->mg_levels.clear();
2382 this->mg_faces.reset();
2383
2384 std::vector<MGVertexDoFs> tmp;
2385
2386 std::swap(this->mg_vertex_dofs, tmp);
2387
2388 this->mg_number_cache.clear();
2389}
2390
2391
2392
2393template <int dim, int spacedim>
2394DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2396 const std::vector<types::global_dof_index> &new_numbers)
2397{
2398 if (hp_capability_enabled)
2399 {
2400 Assert(this->hp_cell_future_fe_indices.size() > 0,
2401 ExcMessage(
2402 "You need to distribute DoFs before you can renumber them."));
2403
2404 AssertDimension(new_numbers.size(), this->n_locally_owned_dofs());
2405
2406 if constexpr (running_in_debug_mode())
2407 {
2408 // assert that the new indices are consecutively numbered if we are
2409 // working on a single processor. this doesn't need to
2410 // hold in the case of a parallel mesh since we map the interval
2411 // [0...n_dofs()) into itself but only globally, not on each processor
2412 if (this->n_locally_owned_dofs() == this->n_dofs())
2413 {
2414 std::vector<types::global_dof_index> tmp(new_numbers);
2415 std::sort(tmp.begin(), tmp.end());
2416 std::vector<types::global_dof_index>::const_iterator p =
2417 tmp.begin();
2419 for (; p != tmp.end(); ++p, ++i)
2420 Assert(*p == i, ExcNewNumbersNotConsecutive(i));
2421 }
2422 else
2423 for (const auto new_number : new_numbers)
2424 Assert(
2425 new_number < this->n_dofs(),
2426 ExcMessage(
2427 "New DoF index is not less than the total number of dofs."));
2428 }
2429
2430 // uncompress the internal storage scheme of dofs on cells so that
2431 // we can access dofs in turns. uncompress in parallel, starting
2432 // with the most expensive levels (the highest ones)
2433 //{
2434 // Threads::TaskGroup<> tg;
2435 // for (int level = this->levels_hp.size() - 1; level >= 0; --level)
2436 // tg += Threads::new_task(
2437 // &::internal::hp::DoFLevel::uncompress_data<dim, spacedim>,
2438 // *this->levels_hp[level],
2439 // this->fe_collection);
2440 // tg.join_all();
2441 //}
2442
2443 // do the renumbering
2444 this->number_cache = this->policy->renumber_dofs(new_numbers);
2445
2446 // now re-compress the dof indices
2447 //{
2448 // Threads::TaskGroup<> tg;
2449 // for (int level = this->levels_hp.size() - 1; level >= 0; --level)
2450 // tg += Threads::new_task(
2451 // &::internal::hp::DoFLevel::compress_data<dim, spacedim>,
2452 // *this->levels_hp[level],
2453 // this->fe_collection);
2454 // tg.join_all();
2455 //}
2456 }
2457 else
2458 {
2459 Assert(this->object_dof_indices.size() > 0,
2460 ExcMessage(
2461 "You need to distribute DoFs before you can renumber them."));
2462
2463 if constexpr (running_in_debug_mode())
2464 {
2465 if (dynamic_cast<const parallel::shared::Triangulation<dim, spacedim>
2466 *>(&*this->tria) != nullptr)
2467 {
2468 Assert(new_numbers.size() == this->n_dofs() ||
2469 new_numbers.size() == this->n_locally_owned_dofs(),
2470 ExcMessage("Incorrect size of the input array."));
2471 }
2472 else if (dynamic_cast<
2473 const parallel::DistributedTriangulationBase<dim, spacedim>
2474 *>(&*this->tria) != nullptr)
2475 {
2476 AssertDimension(new_numbers.size(), this->n_locally_owned_dofs());
2477 }
2478 else
2479 {
2480 AssertDimension(new_numbers.size(), this->n_dofs());
2481 }
2482
2483 // assert that the new indices are consecutively numbered if we are
2484 // working on a single processor. this doesn't need to
2485 // hold in the case of a parallel mesh since we map the interval
2486 // [0...n_dofs()) into itself but only globally, not on each processor
2487 if (this->n_locally_owned_dofs() == this->n_dofs())
2488 {
2489 std::vector<types::global_dof_index> tmp(new_numbers);
2490 std::sort(tmp.begin(), tmp.end());
2491 std::vector<types::global_dof_index>::const_iterator p =
2492 tmp.begin();
2494 for (; p != tmp.end(); ++p, ++i)
2495 Assert(*p == i, ExcNewNumbersNotConsecutive(i));
2496 }
2497 else
2498 for (const auto new_number : new_numbers)
2499 Assert(
2500 new_number < this->n_dofs(),
2501 ExcMessage(
2502 "New DoF index is not less than the total number of dofs."));
2503 }
2504
2505 this->number_cache = this->policy->renumber_dofs(new_numbers);
2506 }
2507}
2508
2509
2510
2511template <int dim, int spacedim>
2512DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2514 const unsigned int level,
2515 const std::vector<types::global_dof_index> &new_numbers)
2516{
2517 AssertThrow(hp_capability_enabled == false, ExcNotImplementedWithHP());
2518
2519 Assert(
2520 this->mg_levels.size() > 0 && this->object_dof_indices.size() > 0,
2521 ExcMessage(
2522 "You need to distribute active and level DoFs before you can renumber level DoFs."));
2523 AssertIndexRange(level, this->get_triangulation().n_global_levels());
2524 AssertDimension(new_numbers.size(),
2525 this->locally_owned_mg_dofs(level).n_elements());
2526
2527 if constexpr (running_in_debug_mode())
2528 {
2529 // assert that the new indices are consecutively numbered if we are
2530 // working on a single processor. this doesn't need to hold in the case of
2531 // a parallel mesh since we map the interval [0...n_dofs(level)) into
2532 // itself but only globally, not on each processor
2533 if (this->n_locally_owned_dofs() == this->n_dofs())
2534 {
2535 std::vector<types::global_dof_index> tmp(new_numbers);
2536 std::sort(tmp.begin(), tmp.end());
2537 std::vector<types::global_dof_index>::const_iterator p = tmp.begin();
2539 for (; p != tmp.end(); ++p, ++i)
2540 Assert(*p == i, ExcNewNumbersNotConsecutive(i));
2541 }
2542 else
2543 for (const auto new_number : new_numbers)
2544 Assert(new_number < this->n_dofs(level),
2545 ExcMessage(
2546 "New DoF index is not less than the total number of dofs."));
2547 }
2548
2549 this->mg_number_cache[level] =
2550 this->policy->renumber_mg_dofs(level, new_numbers);
2551}
2552
2553
2554
2555template <int dim, int spacedim>
2556DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2558 const
2559{
2560 Assert(this->fe_collection.size() > 0, ExcNoFESelected());
2561
2562 switch (dim)
2563 {
2564 case 1:
2565 return this->fe_collection.max_dofs_per_vertex();
2566 case 2:
2567 return (3 * this->fe_collection.max_dofs_per_vertex() +
2568 2 * this->fe_collection.max_dofs_per_line());
2569 case 3:
2570 // we need to take refinement of one boundary face into
2571 // consideration here; in fact, this function returns what
2572 // #max_coupling_between_dofs<2> returns
2573 //
2574 // we assume here, that only four faces meet at the boundary;
2575 // this assumption is not justified and needs to be fixed some
2576 // time. fortunately, omitting it for now does no harm since
2577 // the matrix will cry foul if its requirements are not
2578 // satisfied
2579 return (19 * this->fe_collection.max_dofs_per_vertex() +
2580 28 * this->fe_collection.max_dofs_per_line() +
2581 8 * this->fe_collection.max_dofs_per_quad());
2582 default:
2584 return 0;
2585 }
2586}
2587
2588
2589
2590template <int dim, int spacedim>
2591DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2593{
2594 Assert(this->fe_collection.size() > 0, ExcNoFESelected());
2597}
2598
2599
2600
2601template <int dim, int spacedim>
2602DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2604 const std::vector<types::fe_index> &active_fe_indices)
2605{
2606 Assert(active_fe_indices.size() == this->get_triangulation().n_active_cells(),
2607 ExcDimensionMismatch(active_fe_indices.size(),
2608 this->get_triangulation().n_active_cells()));
2609
2610 this->create_active_fe_table();
2611 // we could set the values directly, since they are stored as
2612 // protected data of this object, but for simplicity we use the
2613 // cell-wise access. this way we also have to pass some debug-mode
2614 // tests which we would have to duplicate ourselves otherwise
2615 for (const auto &cell : this->active_cell_iterators())
2616 if (cell->is_locally_owned())
2617 cell->set_active_fe_index(active_fe_indices[cell->active_cell_index()]);
2618}
2619
2620
2621
2622template <int dim, int spacedim>
2623DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2625 const std::vector<unsigned int> &active_fe_indices)
2626{
2627 set_active_fe_indices(std::vector<types::fe_index>(active_fe_indices.begin(),
2628 active_fe_indices.end()));
2629}
2630
2631
2632
2633template <int dim, int spacedim>
2634DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2635std::vector<types::fe_index> DoFHandler<dim, spacedim>::get_active_fe_indices()
2636 const
2637{
2638 std::vector<types::fe_index> active_fe_indices(
2639 this->get_triangulation().n_active_cells(), numbers::invalid_fe_index);
2640
2641 // we could try to extract the values directly, since they are
2642 // stored as protected data of this object, but for simplicity we
2643 // use the cell-wise access.
2644 for (const auto &cell : this->active_cell_iterators())
2645 if (!cell->is_artificial())
2646 active_fe_indices[cell->active_cell_index()] = cell->active_fe_index();
2647
2648 return active_fe_indices;
2649}
2650
2651
2652
2653template <int dim, int spacedim>
2654DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2656 const std::vector<types::fe_index> &future_fe_indices)
2657{
2658 Assert(future_fe_indices.size() == this->get_triangulation().n_active_cells(),
2659 ExcDimensionMismatch(future_fe_indices.size(),
2660 this->get_triangulation().n_active_cells()));
2661
2662 this->create_active_fe_table();
2663 // we could set the values directly, since they are stored as
2664 // protected data of this object, but for simplicity we use the
2665 // cell-wise access. this way we also have to pass some debug-mode
2666 // tests which we would have to duplicate ourselves otherwise
2667 for (const auto &cell : this->active_cell_iterators())
2668 if (cell->is_locally_owned() &&
2669 future_fe_indices[cell->active_cell_index()] !=
2671 cell->set_future_fe_index(future_fe_indices[cell->active_cell_index()]);
2672}
2673
2674
2675
2676template <int dim, int spacedim>
2677DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2678std::vector<types::fe_index> DoFHandler<dim, spacedim>::get_future_fe_indices()
2679 const
2680{
2681 std::vector<types::fe_index> future_fe_indices(
2682 this->get_triangulation().n_active_cells(), numbers::invalid_fe_index);
2683
2684 // we could try to extract the values directly, since they are
2685 // stored as protected data of this object, but for simplicity we
2686 // use the cell-wise access.
2687 for (const auto &cell : this->active_cell_iterators())
2688 if (cell->is_locally_owned() && cell->future_fe_index_set())
2689 future_fe_indices[cell->active_cell_index()] = cell->future_fe_index();
2690
2691 return future_fe_indices;
2692}
2693
2694
2695
2696template <int dim, int spacedim>
2697DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2699{
2700 // make sure this is called during initialization in hp-mode
2701 Assert(hp_capability_enabled, ExcOnlyAvailableWithHP());
2702
2703 // connect functions to signals of the underlying triangulation
2704 this->tria_listeners.push_back(this->tria->signals.create.connect(
2705 [this]() { this->reinit(*(this->tria)); }));
2706 this->tria_listeners.push_back(
2707 this->tria->signals.clear.connect([this]() { this->clear(); }));
2708
2709 // attach corresponding callback functions dealing with the transfer of
2710 // active FE indices depending on the type of triangulation
2711 if (dynamic_cast<
2712 const ::parallel::fullydistributed::Triangulation<dim, spacedim>
2713 *>(&this->get_triangulation()))
2714 {
2715 // no transfer of active FE indices for this class
2716 }
2717 else if (dynamic_cast<
2718 const ::parallel::distributed::Triangulation<dim, spacedim>
2719 *>(&this->get_triangulation()))
2720 {
2721 // repartitioning signals
2722 this->tria_listeners_for_transfer.push_back(
2723 this->tria->signals.pre_distributed_repartition.connect([this]() {
2724 internal::hp::DoFHandlerImplementation::Implementation::
2725 ensure_absence_of_future_fe_indices<dim, spacedim>(*this);
2726 }));
2727 this->tria_listeners_for_transfer.push_back(
2728 this->tria->signals.pre_distributed_repartition.connect(
2729 [this]() { this->pre_distributed_transfer_action(); }));
2730 this->tria_listeners_for_transfer.push_back(
2731 this->tria->signals.post_distributed_repartition.connect(
2732 [this]() { this->post_distributed_transfer_action(); }));
2733
2734 // refinement signals
2735 this->tria_listeners_for_transfer.push_back(
2736 this->tria->signals.post_p4est_refinement.connect(
2737 [this]() { this->pre_distributed_transfer_action(); }));
2738 this->tria_listeners_for_transfer.push_back(
2739 this->tria->signals.post_distributed_refinement.connect(
2740 [this]() { this->post_distributed_transfer_action(); }));
2741
2742 // serialization signals
2743 this->tria_listeners_for_transfer.push_back(
2744 this->tria->signals.post_distributed_save.connect(
2745 [this]() { this->active_fe_index_transfer.reset(); }));
2746 this->tria_listeners_for_transfer.push_back(
2747 this->tria->signals.post_distributed_load.connect(
2748 [this]() { this->update_active_fe_table(); }));
2749 }
2750 else if (dynamic_cast<
2751 const ::parallel::shared::Triangulation<dim, spacedim> *>(
2752 &this->get_triangulation()) != nullptr)
2753 {
2754 // partitioning signals
2755 this->tria_listeners_for_transfer.push_back(
2756 this->tria->signals.pre_partition.connect([this]() {
2757 internal::hp::DoFHandlerImplementation::Implementation::
2758 ensure_absence_of_future_fe_indices(*this);
2759 }));
2760
2761 // refinement signals
2762 this->tria_listeners_for_transfer.push_back(
2763 this->tria->signals.pre_refinement.connect(
2764 [this]() { this->pre_transfer_action(); }));
2765 this->tria_listeners_for_transfer.push_back(
2766 this->tria->signals.post_refinement.connect(
2767 [this]() { this->post_transfer_action(); }));
2768 }
2769 else
2770 {
2771 // refinement signals
2772 this->tria_listeners_for_transfer.push_back(
2773 this->tria->signals.pre_refinement.connect(
2774 [this]() { this->pre_transfer_action(); }));
2775 this->tria_listeners_for_transfer.push_back(
2776 this->tria->signals.post_refinement.connect(
2777 [this]() { this->post_transfer_action(); }));
2778 }
2779}
2780
2781
2782
2783template <int dim, int spacedim>
2784DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2786{
2787 AssertThrow(hp_capability_enabled == true, ExcOnlyAvailableWithHP());
2788
2789
2790 // Create sufficiently many hp::DoFLevels.
2791 // while (this->levels_hp.size() < this->tria->n_levels())
2792 // this->levels_hp.emplace_back(new ::internal::hp::DoFLevel);
2793
2794 this->hp_cell_active_fe_indices.resize(this->tria->n_levels());
2795 this->hp_cell_future_fe_indices.resize(this->tria->n_levels());
2796
2797 // then make sure that on each level we have the appropriate size
2798 // of active FE indices; preset them to zero, i.e. the default FE
2799 for (unsigned int level = 0; level < this->hp_cell_future_fe_indices.size();
2800 ++level)
2801 {
2802 if (this->hp_cell_active_fe_indices[level].empty() &&
2803 this->hp_cell_future_fe_indices[level].empty())
2804 {
2805 this->hp_cell_active_fe_indices[level].resize(
2806 this->tria->n_raw_cells(level), 0);
2807 this->hp_cell_future_fe_indices[level].resize(
2808 this->tria->n_raw_cells(level), numbers::invalid_fe_index);
2809 }
2810 else
2811 {
2812 // Either the active FE indices have size zero because
2813 // they were just created, or the correct size. Other
2814 // sizes indicate that something went wrong.
2815 Assert(this->hp_cell_active_fe_indices[level].size() ==
2816 this->tria->n_raw_cells(level) &&
2817 this->hp_cell_future_fe_indices[level].size() ==
2818 this->tria->n_raw_cells(level),
2820 }
2821
2822 // it may be that the previous table was compressed; in that
2823 // case, restore the correct active FE index. the fact that
2824 // this no longer matches the indices in the table is of no
2825 // importance because the current function is called at a
2826 // point where we have to recreate the dof_indices tables in
2827 // the levels anyway
2828 // this->levels_hp[level]->normalize_active_fe_indices();
2829 }
2830}
2831
2832
2833
2834template <int dim, int spacedim>
2835DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2837{
2838 // // Normally only one level is added, but if this Triangulation
2839 // // is created by copy_triangulation, it can be more than one level.
2840 // while (this->levels_hp.size() < this->tria->n_levels())
2841 // this->levels_hp.emplace_back(new ::internal::hp::DoFLevel);
2842 //
2843 // // Coarsening can lead to the loss of levels. Hence remove them.
2844 // while (this->levels_hp.size() > this->tria->n_levels())
2845 // {
2846 // // drop the last element. that also releases the memory pointed to
2847 // this->levels_hp.pop_back();
2848 // }
2849
2850 this->hp_cell_active_fe_indices.resize(this->tria->n_levels());
2851 this->hp_cell_active_fe_indices.shrink_to_fit();
2852
2853 this->hp_cell_future_fe_indices.resize(this->tria->n_levels());
2854 this->hp_cell_future_fe_indices.shrink_to_fit();
2855
2856 for (unsigned int i = 0; i < this->hp_cell_future_fe_indices.size(); ++i)
2857 {
2858 // Resize active FE indices vectors. Use zero indicator to extend.
2859 this->hp_cell_active_fe_indices[i].resize(this->tria->n_raw_cells(i), 0);
2860
2861 // Resize future FE indices vectors. Make sure that all
2862 // future FE indices have been cleared after refinement happened.
2863 //
2864 // We have used future FE indices to update all active FE indices
2865 // before refinement happened, thus we are safe to clear them now.
2866 this->hp_cell_future_fe_indices[i].assign(this->tria->n_raw_cells(i),
2868 }
2869}
2870
2871
2872template <int dim, int spacedim>
2873DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2875{
2876 Assert(this->active_fe_index_transfer == nullptr, ExcInternalError());
2877
2878 this->active_fe_index_transfer = std::make_unique<ActiveFEIndexTransfer>();
2879
2882
2885}
2886
2887
2888
2889template <int dim, int spacedim>
2890DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2892{
2893# ifndef DEAL_II_WITH_P4EST
2894 Assert(false,
2895 ExcMessage(
2896 "You are attempting to use a functionality that is only available "
2897 "if deal.II was configured to use p4est, but cmake did not find a "
2898 "valid p4est library."));
2899# else
2900 // the implementation below requires a p:d:T currently
2901 Assert(
2902 (dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
2903 &this->get_triangulation()) != nullptr),
2905
2906 Assert(active_fe_index_transfer == nullptr, ExcInternalError());
2907
2908 active_fe_index_transfer = std::make_unique<ActiveFEIndexTransfer>();
2909
2910 // If we work on a p::d::Triangulation, we have to transfer all
2911 // active FE indices since ownership of cells may change. We will
2912 // use our p::d::CellDataTransfer member to achieve this. Further,
2913 // we prepare the values in such a way that they will correspond to
2914 // the active FE indices on the new mesh.
2915
2916 // Gather all current future FE indices.
2917 active_fe_index_transfer->active_fe_indices.resize(
2918 get_triangulation().n_active_cells(), numbers::invalid_fe_index);
2919
2920 // Collect future FE indices on locally owned and ghost cells.
2921 // The public interface does not allow to access future FE indices
2922 // on ghost cells. However, we need this information here and thus
2923 // call the internal function that does not check for cell ownership.
2926
2927 for (const auto &cell : active_cell_iterators())
2928 if (cell->is_artificial() == false)
2929 active_fe_index_transfer->active_fe_indices[cell->active_cell_index()] =
2932
2933 // Create transfer object and attach to it.
2934 const auto *distributed_tria =
2935 dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
2936 &this->get_triangulation());
2937
2938 active_fe_index_transfer->cell_data_transfer = std::make_unique<
2939 parallel::distributed::
2940 CellDataTransfer<dim, spacedim, std::vector<types::fe_index>>>(
2941 *distributed_tria,
2942 /*transfer_variable_size_data=*/false,
2943 /*refinement_strategy=*/
2944 &::AdaptationStrategies::Refinement::
2945 preserve<dim, spacedim, types::fe_index>,
2946 /*coarsening_strategy=*/
2947 [this](const typename Triangulation<dim, spacedim>::cell_iterator &parent,
2948 const std::vector<types::fe_index> &children_fe_indices)
2949 -> types::fe_index {
2950 return ::internal::hp::DoFHandlerImplementation::Implementation::
2951 determine_fe_from_children<dim, spacedim>(parent,
2952 children_fe_indices,
2953 fe_collection);
2954 });
2955
2956 active_fe_index_transfer->cell_data_transfer
2957 ->prepare_for_coarsening_and_refinement(
2958 active_fe_index_transfer->active_fe_indices);
2959# endif
2960}
2961
2962
2963
2964template <int dim, int spacedim>
2965DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2967{
2968 update_active_fe_table();
2969
2970 Assert(this->active_fe_index_transfer != nullptr, ExcInternalError());
2971
2974
2975 // We have to distribute the information about active FE indices
2976 // of all cells (including the artificial ones) on all processors,
2977 // if a parallel::shared::Triangulation has been used.
2980
2981 // Free memory.
2982 this->active_fe_index_transfer.reset();
2983}
2984
2985
2986
2987template <int dim, int spacedim>
2988DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
2990{
2991# ifndef DEAL_II_WITH_P4EST
2993# else
2994 update_active_fe_table();
2995
2996 Assert(this->active_fe_index_transfer != nullptr, ExcInternalError());
2997
2998 // Unpack active FE indices.
2999 this->active_fe_index_transfer->active_fe_indices.resize(
3000 this->get_triangulation().n_active_cells(), numbers::invalid_fe_index);
3001 this->active_fe_index_transfer->cell_data_transfer->unpack(
3002 this->active_fe_index_transfer->active_fe_indices);
3003
3004 // Update all locally owned active FE indices.
3005 this->set_active_fe_indices(
3006 this->active_fe_index_transfer->active_fe_indices);
3007
3008 // Update active FE indices on ghost cells.
3011
3012 // Free memory.
3013 this->active_fe_index_transfer.reset();
3014# endif
3015}
3016
3017
3018
3019template <int dim, int spacedim>
3020DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3022{
3023# ifndef DEAL_II_WITH_P4EST
3024 Assert(false,
3025 ExcMessage(
3026 "You are attempting to use a functionality that is only available "
3027 "if deal.II was configured to use p4est, but cmake did not find a "
3028 "valid p4est library."));
3029# else
3030 // the implementation below requires a p:d:T currently
3031 Assert(
3032 (dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
3033 &this->get_triangulation()) != nullptr),
3035
3036 Assert(active_fe_index_transfer == nullptr, ExcInternalError());
3037
3038 active_fe_index_transfer = std::make_unique<ActiveFEIndexTransfer>();
3039
3040 // Create transfer object and attach to it.
3041 const auto *distributed_tria =
3042 dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
3043 &this->get_triangulation());
3044
3045 active_fe_index_transfer->cell_data_transfer = std::make_unique<
3046 parallel::distributed::
3047 CellDataTransfer<dim, spacedim, std::vector<types::fe_index>>>(
3048 *distributed_tria,
3049 /*transfer_variable_size_data=*/false,
3050 /*refinement_strategy=*/
3051 &::AdaptationStrategies::Refinement::
3052 preserve<dim, spacedim, types::fe_index>,
3053 /*coarsening_strategy=*/
3054 [this](const typename Triangulation<dim, spacedim>::cell_iterator &parent,
3055 const std::vector<types::fe_index> &children_fe_indices)
3056 -> types::fe_index {
3057 return ::internal::hp::DoFHandlerImplementation::Implementation::
3058 determine_fe_from_children<dim, spacedim>(parent,
3059 children_fe_indices,
3060 fe_collection);
3061 });
3062
3063 // If we work on a p::d::Triangulation, we have to transfer all
3064 // active FE indices since ownership of cells may change.
3065
3066 // Gather all current active FE indices
3067 active_fe_index_transfer->active_fe_indices = get_active_fe_indices();
3068
3069 // Attach to transfer object
3070 active_fe_index_transfer->cell_data_transfer->prepare_for_serialization(
3071 active_fe_index_transfer->active_fe_indices);
3072# endif
3073}
3074
3075
3076
3077template <int dim, int spacedim>
3078DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3080{
3081# ifndef DEAL_II_WITH_P4EST
3082 Assert(false,
3083 ExcMessage(
3084 "You are attempting to use a functionality that is only available "
3085 "if deal.II was configured to use p4est, but cmake did not find a "
3086 "valid p4est library."));
3087# else
3088 // the implementation below requires a p:d:T currently
3089 Assert(
3090 (dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
3091 &this->get_triangulation()) != nullptr),
3093
3094 Assert(active_fe_index_transfer == nullptr, ExcInternalError());
3095
3096 active_fe_index_transfer = std::make_unique<ActiveFEIndexTransfer>();
3097
3098 // Create transfer object and attach to it.
3099 const auto *distributed_tria =
3100 dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
3101 &this->get_triangulation());
3102
3103 active_fe_index_transfer->cell_data_transfer = std::make_unique<
3104 parallel::distributed::
3105 CellDataTransfer<dim, spacedim, std::vector<types::fe_index>>>(
3106 *distributed_tria,
3107 /*transfer_variable_size_data=*/false,
3108 /*refinement_strategy=*/
3109 &::AdaptationStrategies::Refinement::
3110 preserve<dim, spacedim, types::fe_index>,
3111 /*coarsening_strategy=*/
3112 [this](const typename Triangulation<dim, spacedim>::cell_iterator &parent,
3113 const std::vector<types::fe_index> &children_fe_indices)
3114 -> types::fe_index {
3115 return ::internal::hp::DoFHandlerImplementation::Implementation::
3116 determine_fe_from_children<dim, spacedim>(parent,
3117 children_fe_indices,
3118 fe_collection);
3119 });
3120
3121 // Unpack active FE indices.
3122 active_fe_index_transfer->active_fe_indices.resize(
3123 get_triangulation().n_active_cells(), numbers::invalid_fe_index);
3124 active_fe_index_transfer->cell_data_transfer->deserialize(
3125 active_fe_index_transfer->active_fe_indices);
3126
3127 // Update all locally owned active FE indices.
3128 set_active_fe_indices(active_fe_index_transfer->active_fe_indices);
3129
3130 // Update active FE indices on ghost cells.
3133
3134 // Free memory.
3135 active_fe_index_transfer.reset();
3136# endif
3137}
3138
3139
3140
3141template <int dim, int spacedim>
3142DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3144 : coarsest_level(numbers::invalid_unsigned_int)
3145 , finest_level(0)
3146{}
3147
3148
3149
3150template <int dim, int spacedim>
3151DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3153 const unsigned int cl,
3154 const unsigned int fl,
3155 const unsigned int dofs_per_vertex)
3156{
3157 coarsest_level = cl;
3158 finest_level = fl;
3159
3160 if (coarsest_level <= finest_level)
3161 {
3162 const unsigned int n_levels = finest_level - coarsest_level + 1;
3163 const unsigned int n_indices = n_levels * dofs_per_vertex;
3164
3165 indices = std::make_unique<types::global_dof_index[]>(n_indices);
3166 std::fill(indices.get(),
3167 indices.get() + n_indices,
3169 }
3170 else
3171 indices.reset();
3172}
3173
3174
3175
3176template <int dim, int spacedim>
3177DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3179{
3180 return coarsest_level;
3181}
3182
3183
3184
3185template <int dim, int spacedim>
3186DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
3188{
3189 return finest_level;
3190}
3191#endif
3192/*-------------- Explicit Instantiations -------------------------------*/
3193#include "dofs/dof_handler.inst"
3194
3195
3196
*  iterator end()
*  *  iterator begin()
bool at_boundary(const unsigned int i) const
TriaIterator< TriaAccessor< dim - 1, dim, spacedim > > face(const unsigned int i) const
bool is_locally_owned() const
unsigned int active_cell_index() const
bool is_artificial() const
void init(const unsigned int coarsest_level, const unsigned int finest_level, const unsigned int dofs_per_vertex)
unsigned int get_finest_level() const
unsigned int get_coarsest_level() const
cell_iterator end() const
void pre_distributed_transfer_action()
void post_transfer_action()
virtual std::size_t memory_consumption() const
std::vector< types::fe_index > get_future_fe_indices() const
unsigned int max_couplings_between_dofs() const
std::vector< std::unique_ptr<::internal::DoFHandlerImplementation::DoFLevel< dim > > > mg_levels
std::unique_ptr< ActiveFEIndexTransfer > active_fe_index_transfer
hp::FECollection< dim, spacedim > fe_collection
void create_active_fe_table()
static const types::fe_index default_fe_index
std::vector< std::vector< types::fe_index > > hp_cell_future_fe_indices
level_cell_iterator end_mg() const
void renumber_dofs(const std::vector< types::global_dof_index > &new_numbers)
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
level_cell_iterator begin_mg(const unsigned int level=0) const
void distribute_dofs(const FiniteElement< dim, spacedim > &fe)
types::global_dof_index n_boundary_dofs() const
void clear_mg_space()
void connect_to_triangulation_signals()
std::vector< std::vector< types::fe_index > > hp_cell_active_fe_indices
unsigned int offset_type
std::vector< MGVertexDoFs > mg_vertex_dofs
void post_distributed_transfer_action()
std::vector< std::array< std::vector< types::global_dof_index >, dim+1 > > object_dof_indices
const Triangulation< dim, spacedim > & get_triangulation() const
void pre_transfer_action()
void clear_space()
void reinit(const Triangulation< dim, spacedim > &tria)
std::vector< std::array< std::vector< offset_type >, dim+1 > > object_dof_ptr
std::unique_ptr<::internal::DoFHandlerImplementation::DoFFaces< dim > > mg_faces
active_cell_iterator begin_active(const unsigned int level=0) const
std::vector< types::fe_index > get_active_fe_indices() const
void distribute_mg_dofs()
active_cell_iterator end_active(const unsigned int level) const
bool hp_capability_enabled
void initialize_local_block_info()
types::global_dof_index n_dofs() const
void update_active_fe_table()
typename LevelSelector::cell_iterator level_cell_iterator
void prepare_for_serialization_of_active_fe_indices()
cell_iterator begin(const unsigned int level=0) const
std::array< std::vector< offset_type >, dim+1 > hp_object_fe_ptr
void clear()
ObserverPointer< const Triangulation< dim, spacedim >, DoFHandler< dim, spacedim > > tria
std::array< std::vector< types::fe_index >, dim+1 > hp_object_fe_indices
void set_active_fe_indices(const std::vector< types::fe_index > &active_fe_indices)
unsigned int max_couplings_between_boundary_dofs() const
void setup_policy()
void deserialize_active_fe_indices()
void set_future_fe_indices(const std::vector< types::fe_index > &future_fe_indices)
virtual ~DoFHandler() override
unsigned int n_dofs_per_vertex() const
unsigned int n_dofs_per_line() const
bool is_element(const size_type index) const
Definition index_set.h:1901
std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices() const
IteratorState::IteratorStates state() const
@ limit_level_difference_at_vertices
Definition tria.h:1455
virtual const MeshSmoothing & get_mesh_smoothing() const
unsigned int n_raw_lines() const
unsigned int n_raw_faces() const
unsigned int n_levels() const
unsigned int n_raw_cells(const unsigned int level) const
unsigned int max_adjacent_cells() const
bool vertex_used(const unsigned int index) const
unsigned int n_raw_quads() const
unsigned int n_cells() const
Signals signals
Definition tria.h:2602
unsigned int n_vertices() const
unsigned int max_dofs_per_line() const
unsigned int max_dofs_per_hex() const
unsigned int max_dofs_per_vertex() const
unsigned int max_dofs_per_quad() const
constexpr LibraryBuildMode library_build_mode
Definition config.h:66
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:246
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
IteratorRange< active_cell_iterator > active_cell_iterators() const
IteratorRange< level_cell_iterator > mg_cell_iterators() const
IteratorRange< active_cell_iterator > active_cell_iterators_on_level(const unsigned int level) const
IteratorRange< cell_iterator > cell_iterators_on_level(const unsigned int level) const
IteratorRange< cell_iterator > cell_iterators() const
IteratorRange< level_cell_iterator > mg_cell_iterators_on_level(const unsigned int level) const
static ::ExceptionBase & ExcOnlyAvailableWithHP()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcNoDominatedFiniteElementOnChildren()
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNoFESelected()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
static ::ExceptionBase & ExcInconsistentCoarseningFlags()
typename ActiveSelector::cell_iterator cell_iterator
typename ActiveSelector::active_cell_iterator active_cell_iterator
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
Definition tria.h:1624
Task< RT > new_task(const std::function< RT()> &function)
void get_active_fe_indices(const DoFHandler< dim, spacedim > &dof_handler, std::vector< unsigned int > &active_fe_indices)
void exchange_cell_data_to_ghosts(const MeshType &mesh, const std::function< std::optional< DataType >(const typename MeshType::active_cell_iterator &)> &pack, const std::function< void(const typename MeshType::active_cell_iterator &, const DataType &)> &unpack, const std::function< bool(const typename MeshType::active_cell_iterator &)> &cell_filter=always_return< typename MeshType::active_cell_iterator, bool >{true})
@ valid
Iterator points to a valid object.
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
T sum(const T &t, const MPI_Comm mpi_communicator)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:464
Definition hp.h:115
unsigned int n_active_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition tria.cc:15824
unsigned int dominated_future_fe_on_children(const typename DoFHandler< dim, spacedim >::cell_iterator &parent)
void communicate_future_fe_indices(DoFHandler< dim, spacedim > &dof_handler)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
std::string policy_to_string(const ::internal::DoFHandlerImplementation::Policy::PolicyBase< dim, spacedim > &policy)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:267
constexpr unsigned int invalid_unsigned_int
Definition types.h:236
constexpr types::boundary_id internal_face_boundary_id
Definition types.h:327
constexpr types::fe_index invalid_fe_index
Definition types.h:258
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
unsigned int boundary_id
Definition types.h:159
unsigned short int fe_index
Definition types.h:70
unsigned int global_dof_index
Definition types.h:92
boost::signals2::signal< void()> post_distributed_load
Definition tria.h:2591
boost::signals2::signal< void()> post_distributed_refinement
Definition tria.h:2547
boost::signals2::signal< void()> pre_refinement
Definition tria.h:2393
boost::signals2::signal< void()> create
Definition tria.h:2384
boost::signals2::signal< void()> clear
Definition tria.h:2463
boost::signals2::signal< void()> post_refinement
Definition tria.h:2400
boost::signals2::signal< void()> pre_partition
Definition tria.h:2408
boost::signals2::signal< void()> pre_distributed_repartition
Definition tria.h:2554
boost::signals2::signal< void()> post_p4est_refinement
Definition tria.h:2537
boost::signals2::signal< void()> post_distributed_repartition
Definition tria.h:2561
boost::signals2::signal< void()> post_distributed_save
Definition tria.h:2576
static types::fe_index future_fe_index(const DoFCellAccessor< dim, spacedim, level_dof_access > &accessor)
static void reserve_space_mg(DoFHandler< 3, spacedim > &dof_handler)
static void reserve_space(DoFHandler< dim, spacedim > &dof_handler)
static void reserve_subentities(DoFHandler< dim, spacedim > &dof_handler, const unsigned int structdim, const unsigned int n_raw_entities, const T &cell_process)
static unsigned int max_couplings_between_dofs(const DoFHandler< 2, spacedim > &dof_handler)
static void reset_to_empty_objects(DoFHandler< dim, spacedim > &dof_handler)
static unsigned int max_couplings_between_dofs(const DoFHandler< 3, spacedim > &dof_handler)
static void reserve_space_mg(DoFHandler< 1, spacedim > &dof_handler)
static unsigned int max_couplings_between_dofs(const DoFHandler< 1, spacedim > &dof_handler)
static void reserve_space_mg(DoFHandler< 2, spacedim > &dof_handler)
static void reserve_cells(DoFHandler< dim, spacedim > &dof_handler, const unsigned int n_inner_dofs_per_cell)
static void collect_fe_indices_on_cells_to_be_refined(DoFHandler< dim, spacedim > &dof_handler)
static void reserve_space(DoFHandler< 2, spacedim > &dof_handler)
static void reserve_space_cells(DoFHandler< dim, spacedim > &dof_handler)
static types::fe_index dominated_future_fe_on_children(const typename DoFHandler< dim, spacedim >::cell_iterator &parent)
static void distribute_fe_indices_on_refined_cells(DoFHandler< dim, spacedim > &dof_handler)
static void reserve_space(DoFHandler< 3, spacedim > &dof_handler)
static void ensure_absence_of_future_fe_indices(DoFHandler< dim, spacedim > &dof_handler)
static void reserve_space_faces(DoFHandler< dim, spacedim > &dof_handler)
static void communicate_future_fe_indices(DoFHandler< dim, spacedim > &dof_handler)
static void communicate_active_fe_indices(DoFHandler< dim, spacedim > &dof_handler)
static types::fe_index determine_fe_from_children(const typename Triangulation< dim, spacedim >::cell_iterator &, const std::vector< types::fe_index > &children_fe_indices, const ::hp::FECollection< dim, spacedim > &fe_collection)
static void reserve_space_vertices(DoFHandler< dim, spacedim > &dof_handler)
static void reserve_space(DoFHandler< 1, spacedim > &dof_handler)