deal.II version GIT relicensing-6960-g70e9c5b7be 2026-10-22 20:10:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
tria.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) 2010 - 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
16#include <deal.II/base/point.h>
18
21
23#include <deal.II/grid/tria.h>
26
27#include <algorithm>
28#include <fstream>
29#include <iostream>
30#include <limits>
31#include <numeric>
32
33
35
36
37namespace internal
38{
39 namespace parallel
40 {
41 namespace distributed
42 {
43 namespace TriangulationImplementation
44 {
52 template <int dim, int spacedim>
53 void
56 {
57 auto pack =
59 &cell) -> std::uint8_t {
60 if (cell->refine_flag_set())
61 return 1;
62 if (cell->coarsen_flag_set())
63 return 2;
64 return 0;
65 };
66
67 auto unpack =
69 &cell,
70 const std::uint8_t &flag) -> void {
71 cell->clear_coarsen_flag();
72 cell->clear_refine_flag();
73 if (flag == 1)
74 cell->set_refine_flag();
75 else if (flag == 2)
76 cell->set_coarsen_flag();
77 };
78
79 GridTools::exchange_cell_data_to_ghosts<std::uint8_t>(tria,
80 pack,
81 unpack);
82 }
83 } // namespace TriangulationImplementation
84 } // namespace distributed
85 } // namespace parallel
86} // namespace internal
87
88
89
90#ifdef DEAL_II_WITH_P4EST
91
92namespace
93{
94 template <int dim, int spacedim>
95 void
96 get_vertex_to_cell_mappings(
97 const Triangulation<dim, spacedim> &triangulation,
98 std::vector<unsigned int> &vertex_touch_count,
99 std::vector<std::list<
101 unsigned int>>> &vertex_to_cell)
102 {
103 vertex_touch_count.resize(triangulation.n_vertices());
104 vertex_to_cell.resize(triangulation.n_vertices());
105
106 for (const auto &cell : triangulation.active_cell_iterators())
107 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
108 {
109 ++vertex_touch_count[cell->vertex_index(v)];
110 vertex_to_cell[cell->vertex_index(v)].emplace_back(cell, v);
111 }
112 }
113
114
115
116 template <int dim, int spacedim>
117 void
118 get_edge_to_cell_mappings(
119 const Triangulation<dim, spacedim> &triangulation,
120 std::vector<unsigned int> &edge_touch_count,
121 std::vector<std::list<
123 unsigned int>>> &edge_to_cell)
124 {
125 Assert(triangulation.n_levels() == 1, ExcInternalError());
126
127 edge_touch_count.resize(triangulation.n_active_lines());
128 edge_to_cell.resize(triangulation.n_active_lines());
129
130 for (const auto &cell : triangulation.active_cell_iterators())
131 for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell; ++l)
132 {
133 ++edge_touch_count[cell->line(l)->index()];
134 edge_to_cell[cell->line(l)->index()].emplace_back(cell, l);
135 }
136 }
137
138
139
144 template <int dim, int spacedim>
145 void
146 set_vertex_and_cell_info(
147 const Triangulation<dim, spacedim> &triangulation,
148 const std::vector<unsigned int> &vertex_touch_count,
149 const std::vector<std::list<
151 unsigned int>>> &vertex_to_cell,
152 const std::vector<types::global_dof_index>
153 &coarse_cell_to_p4est_tree_permutation,
154 const bool set_vertex_info,
155 typename internal::p4est::types<dim>::connectivity *connectivity)
156 {
157 // copy the vertices into the connectivity structure. the triangulation
158 // exports the array of vertices, but some of the entries are sometimes
159 // unused; this shouldn't be the case for a newly created triangulation,
160 // but make sure
161 //
162 // note that p4est stores coordinates as a triplet of values even in 2d
163 Assert(triangulation.get_used_vertices().size() ==
164 triangulation.get_vertices().size(),
166 Assert(std::find(triangulation.get_used_vertices().begin(),
167 triangulation.get_used_vertices().end(),
168 false) == triangulation.get_used_vertices().end(),
170 if (set_vertex_info == true)
171 for (unsigned int v = 0; v < triangulation.n_vertices(); ++v)
172 {
173 connectivity->vertices[3 * v] = triangulation.get_vertices()[v][0];
174 connectivity->vertices[3 * v + 1] =
175 triangulation.get_vertices()[v][1];
176 connectivity->vertices[3 * v + 2] =
177 (spacedim == 2 ? 0 : triangulation.get_vertices()[v][2]);
178 }
179
180 // next store the tree_to_vertex indices (each tree is here only a single
181 // cell in the coarse mesh). p4est requires vertex numbering in clockwise
182 // orientation
183 //
184 // while we're at it, also copy the neighborship information between cells
186 cell = triangulation.begin_active(),
187 endc = triangulation.end();
188 for (; cell != endc; ++cell)
189 {
190 const unsigned int index =
191 coarse_cell_to_p4est_tree_permutation[cell->index()];
192
193 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
194 {
195 if (set_vertex_info == true)
196 connectivity
198 v] = cell->vertex_index(v);
199 connectivity
201 v] = cell->vertex_index(v);
202 }
203
204 // neighborship information. if a cell is at a boundary, then enter
205 // the index of the cell itself here
206 for (auto f : GeometryInfo<dim>::face_indices())
207 if (cell->face(f)->at_boundary() == false)
208 connectivity
209 ->tree_to_tree[index * GeometryInfo<dim>::faces_per_cell + f] =
210 coarse_cell_to_p4est_tree_permutation[cell->neighbor(f)->index()];
211 else
212 connectivity
213 ->tree_to_tree[index * GeometryInfo<dim>::faces_per_cell + f] =
214 coarse_cell_to_p4est_tree_permutation[cell->index()];
215
216 // fill tree_to_face, which is essentially neighbor_to_neighbor;
217 // however, we have to remap the resulting face number as well
218 for (auto f : GeometryInfo<dim>::face_indices())
219 if (cell->face(f)->at_boundary() == false)
220 {
221 switch (dim)
222 {
223 case 2:
224 {
225 connectivity->tree_to_face
227 cell->neighbor_of_neighbor(f);
228 break;
229 }
230
231 case 3:
232 {
233 /*
234 * The values for tree_to_face are in 0..23 where ttf % 6
235 * gives the face number and ttf / 4 the face orientation
236 * code. The orientation is determined as follows. Let
237 * my_face and other_face be the two face numbers of the
238 * connecting trees in 0..5. Then the first face vertex
239 * of the lower of my_face and other_face connects to a
240 * face vertex numbered 0..3 in the higher of my_face and
241 * other_face. The face orientation is defined as this
242 * number. If my_face == other_face, treating either of
243 * both faces as the lower one leads to the same result.
244 */
245
246 connectivity->tree_to_face[index * 6 + f] =
247 cell->neighbor_of_neighbor(f);
248
249 unsigned int face_idx_list[2] = {
250 f, cell->neighbor_of_neighbor(f)};
252 cell_list[2] = {cell, cell->neighbor(f)};
253 unsigned int smaller_idx = 0;
254
255 if (f > cell->neighbor_of_neighbor(f))
256 smaller_idx = 1;
257
258 unsigned int larger_idx = (smaller_idx + 1) % 2;
259 // smaller = *_list[smaller_idx]
260 // larger = *_list[larger_idx]
261
262 unsigned int v = 0;
263
264 // global vertex index of vertex 0 on face of cell with
265 // smaller local face index
266 unsigned int g_idx = cell_list[smaller_idx]->vertex_index(
268 face_idx_list[smaller_idx],
269 0,
270 cell_list[smaller_idx]->face_orientation(
271 face_idx_list[smaller_idx]),
272 cell_list[smaller_idx]->face_flip(
273 face_idx_list[smaller_idx]),
274 cell_list[smaller_idx]->face_rotation(
275 face_idx_list[smaller_idx])));
276
277 // loop over vertices on face from other cell and compare
278 // global vertex numbers
279 for (unsigned int i = 0;
280 i < GeometryInfo<dim>::vertices_per_face;
281 ++i)
282 {
283 unsigned int idx =
284 cell_list[larger_idx]->vertex_index(
286 face_idx_list[larger_idx], i));
287
288 if (idx == g_idx)
289 {
290 v = i;
291 break;
292 }
293 }
294
295 connectivity->tree_to_face[index * 6 + f] += 6 * v;
296 break;
297 }
298
299 default:
301 }
302 }
303 else
304 connectivity
305 ->tree_to_face[index * GeometryInfo<dim>::faces_per_cell + f] = f;
306 }
307
308 // now fill the vertex information
309 connectivity->ctt_offset[0] = 0;
310 std::partial_sum(vertex_touch_count.begin(),
311 vertex_touch_count.end(),
312 &connectivity->ctt_offset[1]);
313
314 [[maybe_unused]] const typename internal::p4est::types<dim>::locidx
315 num_vtt = std::accumulate(vertex_touch_count.begin(),
316 vertex_touch_count.end(),
317 0u);
318 Assert(connectivity->ctt_offset[triangulation.n_vertices()] == num_vtt,
320
321 for (unsigned int v = 0; v < triangulation.n_vertices(); ++v)
322 {
323 Assert(vertex_to_cell[v].size() == vertex_touch_count[v],
325
326 typename std::list<
327 std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
328 unsigned int>>::const_iterator p =
329 vertex_to_cell[v].begin();
330 for (unsigned int c = 0; c < vertex_touch_count[v]; ++c, ++p)
331 {
332 connectivity->corner_to_tree[connectivity->ctt_offset[v] + c] =
333 coarse_cell_to_p4est_tree_permutation[p->first->index()];
334 connectivity->corner_to_corner[connectivity->ctt_offset[v] + c] =
335 p->second;
336 }
337 }
338 }
339
340
341
342 template <int dim, int spacedim>
343 bool
345 const typename internal::p4est::types<dim>::forest *parallel_forest,
346 const typename internal::p4est::types<dim>::topidx coarse_grid_cell)
347 {
348 Assert(coarse_grid_cell < parallel_forest->connectivity->num_trees,
350 return ((coarse_grid_cell >= parallel_forest->first_local_tree) &&
351 (coarse_grid_cell <= parallel_forest->last_local_tree));
352 }
353
354
355 template <int dim, int spacedim>
356 void
357 delete_all_children_and_self(
359 {
360 if (cell->has_children())
361 for (unsigned int c = 0; c < cell->n_children(); ++c)
362 delete_all_children_and_self<dim, spacedim>(cell->child(c));
363 else
364 cell->set_coarsen_flag();
365 }
366
367
368
369 template <int dim, int spacedim>
370 void
371 delete_all_children(
373 {
374 if (cell->has_children())
375 for (unsigned int c = 0; c < cell->n_children(); ++c)
376 delete_all_children_and_self<dim, spacedim>(cell->child(c));
377 }
378
379
380 template <int dim, int spacedim>
381 void
382 determine_level_subdomain_id_recursively(
383 const typename internal::p4est::types<dim>::tree &tree,
384 const typename internal::p4est::types<dim>::locidx &tree_index,
385 const typename Triangulation<dim, spacedim>::cell_iterator &dealii_cell,
386 const typename internal::p4est::types<dim>::quadrant &p4est_cell,
388 const types::subdomain_id my_subdomain,
389 const std::vector<std::vector<bool>> &marked_vertices)
390 {
391 if (dealii_cell->level_subdomain_id() == numbers::artificial_subdomain_id)
392 {
393 // important: only assign the level_subdomain_id if it is a ghost cell
394 // even though we could fill in all.
395 bool used = false;
396 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
397 {
398 if (marked_vertices[dealii_cell->level()]
399 [dealii_cell->vertex_index(v)])
400 {
401 used = true;
402 break;
403 }
404 }
405
406 // Special case: if this cell is active we might be a ghost neighbor
407 // to a locally owned cell across a vertex that is finer.
408 // Example (M= my, O=dealii_cell, owned by somebody else):
409 // *------*
410 // | |
411 // | O |
412 // | |
413 // *---*---*------*
414 // | M | M |
415 // *---*---*
416 // | | M |
417 // *---*---*
418 if (!used && dealii_cell->is_active() &&
419 dealii_cell->is_artificial() == false &&
420 dealii_cell->level() + 1 < static_cast<int>(marked_vertices.size()))
421 {
422 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
423 {
424 if (marked_vertices[dealii_cell->level() + 1]
425 [dealii_cell->vertex_index(v)])
426 {
427 used = true;
428 break;
429 }
430 }
431 }
432
433 // Like above, but now the other way around
434 if (!used && dealii_cell->is_active() &&
435 dealii_cell->is_artificial() == false && dealii_cell->level() > 0)
436 {
437 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
438 {
439 if (marked_vertices[dealii_cell->level() - 1]
440 [dealii_cell->vertex_index(v)])
441 {
442 used = true;
443 break;
444 }
445 }
446 }
447
448 if (used)
449 {
451 &forest, tree_index, &p4est_cell, my_subdomain);
452 Assert((owner != -2) && (owner != -1),
453 ExcMessage("p4est should know the owner."));
454 dealii_cell->set_level_subdomain_id(owner);
455 }
456 }
457
458 if (dealii_cell->has_children())
459 {
462 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
463 ++c)
465
466
468 p4est_child);
469
470 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
471 ++c)
472 {
473 determine_level_subdomain_id_recursively<dim, spacedim>(
474 tree,
475 tree_index,
476 dealii_cell->child(c),
477 p4est_child[c],
478 forest,
479 my_subdomain,
480 marked_vertices);
481 }
482 }
483 }
484
485
486 template <int dim, int spacedim>
487 void
488 match_tree_recursively(
489 const typename internal::p4est::types<dim>::tree &tree,
490 const typename Triangulation<dim, spacedim>::cell_iterator &dealii_cell,
491 const typename internal::p4est::types<dim>::quadrant &p4est_cell,
492 const typename internal::p4est::types<dim>::forest &forest,
493 const types::subdomain_id my_subdomain)
494 {
495 // check if this cell exists in the local p4est cell
496 if (sc_array_bsearch(const_cast<sc_array_t *>(&tree.quadrants),
497 &p4est_cell,
499 -1)
500 {
501 // yes, cell found in local part of p4est
502 delete_all_children<dim, spacedim>(dealii_cell);
503 if (dealii_cell->is_active())
504 dealii_cell->set_subdomain_id(my_subdomain);
505 }
506 else
507 {
508 // no, cell not found in local part of p4est. this means that the
509 // local part is more refined than the current cell. if this cell has
510 // no children of its own, we need to refine it, and if it does
511 // already have children then loop over all children and see if they
512 // are locally available as well
513 if (dealii_cell->is_active())
514 dealii_cell->set_refine_flag();
515 else
516 {
519 for (unsigned int c = 0;
520 c < GeometryInfo<dim>::max_children_per_cell;
521 ++c)
523
525 p4est_child);
526
527 for (unsigned int c = 0;
528 c < GeometryInfo<dim>::max_children_per_cell;
529 ++c)
531 const_cast<typename internal::p4est::types<dim>::tree *>(
532 &tree),
533 &p4est_child[c]) == false)
534 {
535 // no, this child is locally not available in the p4est.
536 // delete all its children but, because this may not be
537 // successful, make sure to mark all children recursively
538 // as not local.
539 delete_all_children<dim, spacedim>(dealii_cell->child(c));
540 dealii_cell->child(c)->recursively_set_subdomain_id(
542 }
543 else
544 {
545 // at least some part of the tree rooted in this child is
546 // locally available
547 match_tree_recursively<dim, spacedim>(tree,
548 dealii_cell->child(c),
549 p4est_child[c],
550 forest,
551 my_subdomain);
552 }
553 }
554 }
555 }
556
557
558 template <int dim, int spacedim>
559 void
560 match_quadrant(
561 const ::Triangulation<dim, spacedim> *tria,
562 unsigned int dealii_index,
563 const typename internal::p4est::types<dim>::quadrant &ghost_quadrant,
564 types::subdomain_id ghost_owner)
565 {
566 const int l = ghost_quadrant.level;
567
568 for (int i = 0; i < l; ++i)
569 {
571 i,
572 dealii_index);
573 if (cell->is_active())
574 {
575 cell->clear_coarsen_flag();
576 cell->set_refine_flag();
577 return;
578 }
579
580 const int child_id =
582 i + 1);
583 dealii_index = cell->child_index(child_id);
584 }
585
587 l,
588 dealii_index);
589 if (cell->has_children())
590 delete_all_children<dim, spacedim>(cell);
591 else
592 {
593 cell->clear_coarsen_flag();
594 cell->set_subdomain_id(ghost_owner);
595 }
596 }
597
598 template <int dim>
599 class PartitionSearch
600 {
601 public:
602 PartitionSearch()
603 {
604 Assert(dim > 1, ExcNotImplemented());
605 }
606
607 PartitionSearch(const PartitionSearch<dim> &other) = delete;
608
609 PartitionSearch<dim> &
610 operator=(const PartitionSearch<dim> &other) = delete;
611
612 public:
622 static int
623 local_quadrant_fn(typename internal::p4est::types<dim>::forest *forest,
624 typename internal::p4est::types<dim>::topidx which_tree,
625 typename internal::p4est::types<dim>::quadrant *quadrant,
626 int rank_begin,
627 int rank_end,
628 void *point);
629
642 static int
643 local_point_fn(typename internal::p4est::types<dim>::forest *forest,
644 typename internal::p4est::types<dim>::topidx which_tree,
645 typename internal::p4est::types<dim>::quadrant *quadrant,
646 int rank_begin,
647 int rank_end,
648 void *point);
649
650 private:
655 class QuadrantData
656 {
657 public:
658 QuadrantData();
659
660 void
661 set_cell_vertices(
663 typename internal::p4est::types<dim>::topidx which_tree,
664 typename internal::p4est::types<dim>::quadrant *quadrant,
666 quad_length_on_level);
667
668 void
669 initialize_mapping();
670
672 map_real_to_unit_cell(const Point<dim> &p) const;
673
674 bool
675 is_in_this_quadrant(const Point<dim> &p) const;
676
677 private:
678 std::vector<Point<dim>> cell_vertices;
679
684 FullMatrix<double> quadrant_mapping_matrix;
685
686 bool are_vertices_initialized;
687
688 bool is_reference_mapping_initialized;
689 };
690
694 QuadrantData quadrant_data;
695 }; // class PartitionSearch
696
697
698
699 template <int dim>
700 int
701 PartitionSearch<dim>::local_quadrant_fn(
703 typename internal::p4est::types<dim>::topidx which_tree,
704 typename internal::p4est::types<dim>::quadrant *quadrant,
705 int /* rank_begin */,
706 int /* rank_end */,
707 void * /* this is always nullptr */ point)
708 {
709 // point must be nullptr here
710 Assert(point == nullptr, ::ExcInternalError());
711
712 // we need the user pointer
713 // note that this is not available since function is static
714 PartitionSearch<dim> *this_object =
715 reinterpret_cast<PartitionSearch<dim> *>(forest->user_pointer);
716
717 // Avoid p4est macros, instead do bitshifts manually with fixed size types
719 quad_length_on_level =
720 1 << (static_cast<typename internal::p4est::types<dim>::quadrant_coord>(
721 (dim == 2 ? P4EST_MAXLEVEL : P8EST_MAXLEVEL)) -
723 quadrant->level));
724
725 this_object->quadrant_data.set_cell_vertices(forest,
726 which_tree,
727 quadrant,
728 quad_length_on_level);
729
730 // from cell vertices we can initialize the mapping
731 this_object->quadrant_data.initialize_mapping();
732
733 // always return true since we must decide by point
734 return /* true */ 1;
735 }
736
737
738
739 template <int dim>
740 int
741 PartitionSearch<dim>::local_point_fn(
743 typename internal::p4est::types<dim>::topidx /* which_tree */,
744 typename internal::p4est::types<dim>::quadrant * /* quadrant */,
745 int rank_begin,
746 int rank_end,
747 void *point)
748 {
749 // point must NOT be be nullptr here
750 Assert(point != nullptr, ::ExcInternalError());
751
752 // we need the user pointer
753 // note that this is not available since function is static
754 PartitionSearch<dim> *this_object =
755 reinterpret_cast<PartitionSearch<dim> *>(forest->user_pointer);
756
757 // point with rank as double pointer
758 double *this_point_dptr = static_cast<double *>(point);
759
760 Point<dim> this_point =
761 (dim == 2 ? Point<dim>(this_point_dptr[0], this_point_dptr[1]) :
762 Point<dim>(this_point_dptr[0],
763 this_point_dptr[1],
764 this_point_dptr[2]));
765
766 // use reference mapping to decide whether this point is in this quadrant
767 const bool is_in_this_quadrant =
768 this_object->quadrant_data.is_in_this_quadrant(this_point);
769
770
771
772 if (!is_in_this_quadrant)
773 {
774 // no need to search further, stop recursion
775 return /* false */ 0;
776 }
777
778
779
780 // From here we have a candidate
781 if (rank_begin < rank_end)
782 {
783 // continue recursion
784 return /* true */ 1;
785 }
786
787 // Now, we know that the point is found (rank_begin==rank_end) and we have
788 // the MPI rank, so no need to search further.
789 this_point_dptr[dim] = static_cast<double>(rank_begin);
790
791 // stop recursion.
792 return /* false */ 0;
793 }
794
795
796
797 template <int dim>
798 bool
799 PartitionSearch<dim>::QuadrantData::is_in_this_quadrant(
800 const Point<dim> &p) const
801 {
802 const Point<dim> p_ref = map_real_to_unit_cell(p);
803
805 }
806
807
808
809 template <int dim>
811 PartitionSearch<dim>::QuadrantData::map_real_to_unit_cell(
812 const Point<dim> &p) const
813 {
814 Assert(is_reference_mapping_initialized,
816 "Cell vertices and mapping coefficients must be fully "
817 "initialized before transforming a point to the unit cell."));
818
819 Point<dim> p_out;
820
821 if (dim == 2)
822 {
823 for (unsigned int alpha = 0;
824 alpha < GeometryInfo<dim>::vertices_per_cell;
825 ++alpha)
826 {
827 const Point<dim> &p_ref =
829
830 p_out += (quadrant_mapping_matrix(alpha, 0) +
831 quadrant_mapping_matrix(alpha, 1) * p(0) +
832 quadrant_mapping_matrix(alpha, 2) * p(1) +
833 quadrant_mapping_matrix(alpha, 3) * p(0) * p(1)) *
834 p_ref;
835 }
836 }
837 else
838 {
839 for (unsigned int alpha = 0;
840 alpha < GeometryInfo<dim>::vertices_per_cell;
841 ++alpha)
842 {
843 const Point<dim> &p_ref =
845
846 p_out += (quadrant_mapping_matrix(alpha, 0) +
847 quadrant_mapping_matrix(alpha, 1) * p(0) +
848 quadrant_mapping_matrix(alpha, 2) * p(1) +
849 quadrant_mapping_matrix(alpha, 3) * p(2) +
850 quadrant_mapping_matrix(alpha, 4) * p(0) * p(1) +
851 quadrant_mapping_matrix(alpha, 5) * p(1) * p(2) +
852 quadrant_mapping_matrix(alpha, 6) * p(0) * p(2) +
853 quadrant_mapping_matrix(alpha, 7) * p(0) * p(1) * p(2)) *
854 p_ref;
855 }
856 }
857
858 return p_out;
859 }
860
861
862 template <int dim>
863 PartitionSearch<dim>::QuadrantData::QuadrantData()
864 : cell_vertices(GeometryInfo<dim>::vertices_per_cell)
865 , quadrant_mapping_matrix(GeometryInfo<dim>::vertices_per_cell,
866 GeometryInfo<dim>::vertices_per_cell)
867 , are_vertices_initialized(false)
868 , is_reference_mapping_initialized(false)
869 {}
870
871
872
873 template <int dim>
874 void
875 PartitionSearch<dim>::QuadrantData::initialize_mapping()
876 {
877 Assert(
878 are_vertices_initialized,
880 "Cell vertices must be initialized before the cell mapping can be filled."));
881
884
885 if (dim == 2)
886 {
887 for (unsigned int alpha = 0;
888 alpha < GeometryInfo<dim>::vertices_per_cell;
889 ++alpha)
890 {
891 // point matrix to be inverted
892 point_matrix(0, alpha) = 1;
893 point_matrix(1, alpha) = cell_vertices[alpha](0);
894 point_matrix(2, alpha) = cell_vertices[alpha](1);
895 point_matrix(3, alpha) =
896 cell_vertices[alpha](0) * cell_vertices[alpha](1);
897 }
898
899 /*
900 * Rows of quadrant_mapping_matrix are the coefficients of the basis
901 * on the physical cell
902 */
903 quadrant_mapping_matrix.invert(point_matrix);
904 }
905 else
906 {
907 for (unsigned int alpha = 0;
908 alpha < GeometryInfo<dim>::vertices_per_cell;
909 ++alpha)
910 {
911 // point matrix to be inverted
912 point_matrix(0, alpha) = 1;
913 point_matrix(1, alpha) = cell_vertices[alpha](0);
914 point_matrix(2, alpha) = cell_vertices[alpha](1);
915 point_matrix(3, alpha) = cell_vertices[alpha](2);
916 point_matrix(4, alpha) =
917 cell_vertices[alpha](0) * cell_vertices[alpha](1);
918 point_matrix(5, alpha) =
919 cell_vertices[alpha](1) * cell_vertices[alpha](2);
920 point_matrix(6, alpha) =
921 cell_vertices[alpha](0) * cell_vertices[alpha](2);
922 point_matrix(7, alpha) = cell_vertices[alpha](0) *
923 cell_vertices[alpha](1) *
924 cell_vertices[alpha](2);
925 }
926
927 /*
928 * Rows of quadrant_mapping_matrix are the coefficients of the basis
929 * on the physical cell
930 */
931 quadrant_mapping_matrix.invert(point_matrix);
932 }
933
934 is_reference_mapping_initialized = true;
935 }
936
937
938
939 template <>
940 void
941 PartitionSearch<2>::QuadrantData::set_cell_vertices(
942 typename internal::p4est::types<2>::forest *forest,
943 typename internal::p4est::types<2>::topidx which_tree,
944 typename internal::p4est::types<2>::quadrant *quadrant,
946 quad_length_on_level)
947 {
948 constexpr unsigned int dim = 2;
949
950 // p4est for some reason always needs double vxyz[3] as last argument to
951 // quadrant_coord_to_vertex
952 double corner_point[dim + 1] = {0};
953
954 // A lambda to avoid code duplication.
955 const auto copy_vertex = [&](unsigned int vertex_index) -> void {
956 // copy into local struct
957 for (unsigned int d = 0; d < dim; ++d)
958 {
959 cell_vertices[vertex_index](d) = corner_point[d];
960 // reset
961 corner_point[d] = 0;
962 }
963 };
964
965 // Fill points of QuadrantData in lexicographic order
966 /*
967 * Corner #0
968 */
969 unsigned int vertex_index = 0;
971 forest->connectivity, which_tree, quadrant->x, quadrant->y, corner_point);
972
973 // copy into local struct
974 copy_vertex(vertex_index);
975
976 /*
977 * Corner #1
978 */
979 vertex_index = 1;
981 forest->connectivity,
982 which_tree,
983 quadrant->x + quad_length_on_level,
984 quadrant->y,
985 corner_point);
986
987 // copy into local struct
988 copy_vertex(vertex_index);
989
990 /*
991 * Corner #2
992 */
993 vertex_index = 2;
995 forest->connectivity,
996 which_tree,
997 quadrant->x,
998 quadrant->y + quad_length_on_level,
999 corner_point);
1000
1001 // copy into local struct
1002 copy_vertex(vertex_index);
1003
1004 /*
1005 * Corner #3
1006 */
1007 vertex_index = 3;
1009 forest->connectivity,
1010 which_tree,
1011 quadrant->x + quad_length_on_level,
1012 quadrant->y + quad_length_on_level,
1013 corner_point);
1014
1015 // copy into local struct
1016 copy_vertex(vertex_index);
1017
1018 are_vertices_initialized = true;
1019 }
1020
1021
1022
1023 template <>
1024 void
1025 PartitionSearch<3>::QuadrantData::set_cell_vertices(
1026 typename internal::p4est::types<3>::forest *forest,
1027 typename internal::p4est::types<3>::topidx which_tree,
1028 typename internal::p4est::types<3>::quadrant *quadrant,
1030 quad_length_on_level)
1031 {
1032 constexpr unsigned int dim = 3;
1033
1034 double corner_point[dim] = {0};
1035
1036 // A lambda to avoid code duplication.
1037 auto copy_vertex = [&](unsigned int vertex_index) -> void {
1038 // copy into local struct
1039 for (unsigned int d = 0; d < dim; ++d)
1040 {
1041 cell_vertices[vertex_index](d) = corner_point[d];
1042 // reset
1043 corner_point[d] = 0;
1044 }
1045 };
1046
1047 // Fill points of QuadrantData in lexicographic order
1048 /*
1049 * Corner #0
1050 */
1051 unsigned int vertex_index = 0;
1053 forest->connectivity,
1054 which_tree,
1055 quadrant->x,
1056 quadrant->y,
1057 quadrant->z,
1058 corner_point);
1059
1060 // copy into local struct
1061 copy_vertex(vertex_index);
1062
1063
1064 /*
1065 * Corner #1
1066 */
1067 vertex_index = 1;
1069 forest->connectivity,
1070 which_tree,
1071 quadrant->x + quad_length_on_level,
1072 quadrant->y,
1073 quadrant->z,
1074 corner_point);
1075
1076 // copy into local struct
1077 copy_vertex(vertex_index);
1078
1079 /*
1080 * Corner #2
1081 */
1082 vertex_index = 2;
1084 forest->connectivity,
1085 which_tree,
1086 quadrant->x,
1087 quadrant->y + quad_length_on_level,
1088 quadrant->z,
1089 corner_point);
1090
1091 // copy into local struct
1092 copy_vertex(vertex_index);
1093
1094 /*
1095 * Corner #3
1096 */
1097 vertex_index = 3;
1099 forest->connectivity,
1100 which_tree,
1101 quadrant->x + quad_length_on_level,
1102 quadrant->y + quad_length_on_level,
1103 quadrant->z,
1104 corner_point);
1105
1106 // copy into local struct
1107 copy_vertex(vertex_index);
1108
1109 /*
1110 * Corner #4
1111 */
1112 vertex_index = 4;
1114 forest->connectivity,
1115 which_tree,
1116 quadrant->x,
1117 quadrant->y,
1118 quadrant->z + quad_length_on_level,
1119 corner_point);
1120
1121 // copy into local struct
1122 copy_vertex(vertex_index);
1123
1124 /*
1125 * Corner #5
1126 */
1127 vertex_index = 5;
1129 forest->connectivity,
1130 which_tree,
1131 quadrant->x + quad_length_on_level,
1132 quadrant->y,
1133 quadrant->z + quad_length_on_level,
1134 corner_point);
1135
1136 // copy into local struct
1137 copy_vertex(vertex_index);
1138
1139 /*
1140 * Corner #6
1141 */
1142 vertex_index = 6;
1144 forest->connectivity,
1145 which_tree,
1146 quadrant->x,
1147 quadrant->y + quad_length_on_level,
1148 quadrant->z + quad_length_on_level,
1149 corner_point);
1150
1151 // copy into local struct
1152 copy_vertex(vertex_index);
1153
1154 /*
1155 * Corner #7
1156 */
1157 vertex_index = 7;
1159 forest->connectivity,
1160 which_tree,
1161 quadrant->x + quad_length_on_level,
1162 quadrant->y + quad_length_on_level,
1163 quadrant->z + quad_length_on_level,
1164 corner_point);
1165
1166 // copy into local struct
1167 copy_vertex(vertex_index);
1168
1169
1170 are_vertices_initialized = true;
1171 }
1172
1173
1174
1180 template <int dim, int spacedim>
1181 class RefineAndCoarsenList
1182 {
1183 public:
1184 RefineAndCoarsenList(const Triangulation<dim, spacedim> &triangulation,
1185 const std::vector<types::global_dof_index>
1186 &p4est_tree_to_coarse_cell_permutation,
1187 const types::subdomain_id my_subdomain);
1188
1197 static int
1198 refine_callback(
1199 typename internal::p4est::types<dim>::forest *forest,
1200 typename internal::p4est::types<dim>::topidx coarse_cell_index,
1201 typename internal::p4est::types<dim>::quadrant *quadrant);
1202
1207 static int
1208 coarsen_callback(
1209 typename internal::p4est::types<dim>::forest *forest,
1210 typename internal::p4est::types<dim>::topidx coarse_cell_index,
1211 typename internal::p4est::types<dim>::quadrant *children[]);
1212
1213 bool
1214 pointers_are_at_end() const;
1215
1216 private:
1217 std::vector<typename internal::p4est::types<dim>::quadrant> refine_list;
1218 typename std::vector<typename internal::p4est::types<dim>::quadrant>::
1219 const_iterator current_refine_pointer;
1220
1221 std::vector<typename internal::p4est::types<dim>::quadrant> coarsen_list;
1222 typename std::vector<typename internal::p4est::types<dim>::quadrant>::
1223 const_iterator current_coarsen_pointer;
1224
1225 void
1226 build_lists(
1228 const typename internal::p4est::types<dim>::quadrant &p4est_cell,
1229 const types::subdomain_id myid);
1230 };
1231
1232
1233
1234 template <int dim, int spacedim>
1235 bool
1236 RefineAndCoarsenList<dim, spacedim>::pointers_are_at_end() const
1237 {
1238 return ((current_refine_pointer == refine_list.end()) &&
1239 (current_coarsen_pointer == coarsen_list.end()));
1240 }
1241
1242
1243
1244 template <int dim, int spacedim>
1245 RefineAndCoarsenList<dim, spacedim>::RefineAndCoarsenList(
1246 const Triangulation<dim, spacedim> &triangulation,
1247 const std::vector<types::global_dof_index>
1248 &p4est_tree_to_coarse_cell_permutation,
1249 const types::subdomain_id my_subdomain)
1250 {
1251 // count how many flags are set and allocate that much memory
1252 unsigned int n_refine_flags = 0, n_coarsen_flags = 0;
1253 for (const auto &cell : triangulation.active_cell_iterators())
1254 {
1255 // skip cells that are not local
1256 if (cell->subdomain_id() != my_subdomain)
1257 continue;
1258
1259 if (cell->refine_flag_set())
1260 ++n_refine_flags;
1261 else if (cell->coarsen_flag_set())
1262 ++n_coarsen_flags;
1263 }
1264
1265 refine_list.reserve(n_refine_flags);
1266 coarsen_list.reserve(n_coarsen_flags);
1267
1268
1269 // now build the lists of cells that are flagged. note that p4est will
1270 // traverse its cells in the order in which trees appear in the
1271 // forest. this order is not the same as the order of coarse cells in the
1272 // deal.II Triangulation because we have translated everything by the
1273 // coarse_cell_to_p4est_tree_permutation permutation. in order to make
1274 // sure that the output array is already in the correct order, traverse
1275 // our coarse cells in the same order in which p4est will:
1276 for (unsigned int c = 0; c < triangulation.n_cells(0); ++c)
1277 {
1278 unsigned int coarse_cell_index =
1279 p4est_tree_to_coarse_cell_permutation[c];
1280
1282 &triangulation, 0, coarse_cell_index);
1283
1284 typename internal::p4est::types<dim>::quadrant p4est_cell;
1286 /*level=*/0,
1287 /*index=*/0);
1288 p4est_cell.p.which_tree = c;
1289 build_lists(cell, p4est_cell, my_subdomain);
1290 }
1291
1292
1293 Assert(refine_list.size() == n_refine_flags, ExcInternalError());
1294 Assert(coarsen_list.size() == n_coarsen_flags, ExcInternalError());
1295
1296 // make sure that our ordering in fact worked
1297 for (unsigned int i = 1; i < refine_list.size(); ++i)
1298 Assert(refine_list[i].p.which_tree >= refine_list[i - 1].p.which_tree,
1300 for (unsigned int i = 1; i < coarsen_list.size(); ++i)
1301 Assert(coarsen_list[i].p.which_tree >= coarsen_list[i - 1].p.which_tree,
1303
1304 current_refine_pointer = refine_list.begin();
1305 current_coarsen_pointer = coarsen_list.begin();
1306 }
1307
1308
1309
1310 template <int dim, int spacedim>
1311 void
1312 RefineAndCoarsenList<dim, spacedim>::build_lists(
1314 const typename internal::p4est::types<dim>::quadrant &p4est_cell,
1315 const types::subdomain_id my_subdomain)
1316 {
1317 if (cell->is_active())
1318 {
1319 if (cell->subdomain_id() == my_subdomain)
1320 {
1321 if (cell->refine_flag_set())
1322 refine_list.push_back(p4est_cell);
1323 else if (cell->coarsen_flag_set())
1324 coarsen_list.push_back(p4est_cell);
1325 }
1326 }
1327 else
1328 {
1331 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1332 ++c)
1335 p4est_child);
1336 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1337 ++c)
1338 {
1339 p4est_child[c].p.which_tree = p4est_cell.p.which_tree;
1340 build_lists(cell->child(c), p4est_child[c], my_subdomain);
1341 }
1342 }
1343 }
1344
1345
1346 template <int dim, int spacedim>
1347 int
1348 RefineAndCoarsenList<dim, spacedim>::refine_callback(
1349 typename internal::p4est::types<dim>::forest *forest,
1350 typename internal::p4est::types<dim>::topidx coarse_cell_index,
1351 typename internal::p4est::types<dim>::quadrant *quadrant)
1352 {
1353 RefineAndCoarsenList<dim, spacedim> *this_object =
1354 reinterpret_cast<RefineAndCoarsenList<dim, spacedim> *>(
1355 forest->user_pointer);
1356
1357 // if there are no more cells in our list the current cell can't be
1358 // flagged for refinement
1359 if (this_object->current_refine_pointer == this_object->refine_list.end())
1360 return 0;
1361
1362 Assert(coarse_cell_index <=
1363 this_object->current_refine_pointer->p.which_tree,
1365
1366 // if p4est hasn't yet reached the tree of the next flagged cell the
1367 // current cell can't be flagged for refinement
1368 if (coarse_cell_index < this_object->current_refine_pointer->p.which_tree)
1369 return 0;
1370
1371 // now we're in the right tree in the forest
1372 Assert(coarse_cell_index <=
1373 this_object->current_refine_pointer->p.which_tree,
1375
1376 // make sure that the p4est loop over cells hasn't gotten ahead of our own
1377 // pointer
1379 quadrant, &*this_object->current_refine_pointer) <= 0,
1381
1382 // now, if the p4est cell is one in the list, it is supposed to be refined
1384 quadrant, &*this_object->current_refine_pointer))
1385 {
1386 ++this_object->current_refine_pointer;
1387 return 1;
1388 }
1389
1390 // p4est cell is not in list
1391 return 0;
1392 }
1393
1394
1395
1396 template <int dim, int spacedim>
1397 int
1398 RefineAndCoarsenList<dim, spacedim>::coarsen_callback(
1399 typename internal::p4est::types<dim>::forest *forest,
1400 typename internal::p4est::types<dim>::topidx coarse_cell_index,
1401 typename internal::p4est::types<dim>::quadrant *children[])
1402 {
1403 RefineAndCoarsenList<dim, spacedim> *this_object =
1404 reinterpret_cast<RefineAndCoarsenList<dim, spacedim> *>(
1405 forest->user_pointer);
1406
1407 // if there are no more cells in our list the current cell can't be
1408 // flagged for coarsening
1409 if (this_object->current_coarsen_pointer == this_object->coarsen_list.end())
1410 return 0;
1411
1412 Assert(coarse_cell_index <=
1413 this_object->current_coarsen_pointer->p.which_tree,
1415
1416 // if p4est hasn't yet reached the tree of the next flagged cell the
1417 // current cell can't be flagged for coarsening
1418 if (coarse_cell_index < this_object->current_coarsen_pointer->p.which_tree)
1419 return 0;
1420
1421 // now we're in the right tree in the forest
1422 Assert(coarse_cell_index <=
1423 this_object->current_coarsen_pointer->p.which_tree,
1425
1426 // make sure that the p4est loop over cells hasn't gotten ahead of our own
1427 // pointer
1429 children[0], &*this_object->current_coarsen_pointer) <= 0,
1431
1432 // now, if the p4est cell is one in the list, it is supposed to be
1433 // coarsened
1435 children[0], &*this_object->current_coarsen_pointer))
1436 {
1437 // move current pointer one up
1438 ++this_object->current_coarsen_pointer;
1439
1440 // note that the next 3 cells in our list need to correspond to the
1441 // other siblings of the cell we have just found
1442 for (unsigned int c = 1; c < GeometryInfo<dim>::max_children_per_cell;
1443 ++c)
1444 {
1446 children[c], &*this_object->current_coarsen_pointer),
1448 ++this_object->current_coarsen_pointer;
1449 }
1450
1451 return 1;
1452 }
1453
1454 // p4est cell is not in list
1455 return 0;
1456 }
1457
1458
1459
1466 template <int dim, int spacedim>
1467 class PartitionWeights
1468 {
1469 public:
1475 explicit PartitionWeights(const std::vector<unsigned int> &cell_weights);
1476
1484 static int
1485 cell_weight(typename internal::p4est::types<dim>::forest *forest,
1486 typename internal::p4est::types<dim>::topidx coarse_cell_index,
1487 typename internal::p4est::types<dim>::quadrant *quadrant);
1488
1489 private:
1490 std::vector<unsigned int> cell_weights_list;
1491 std::vector<unsigned int>::const_iterator current_pointer;
1492 };
1493
1494
1495 template <int dim, int spacedim>
1496 PartitionWeights<dim, spacedim>::PartitionWeights(
1497 const std::vector<unsigned int> &cell_weights)
1498 : cell_weights_list(cell_weights)
1499 {
1500 // set the current pointer to the first element of the list, given that
1501 // we will walk through it sequentially
1502 current_pointer = cell_weights_list.begin();
1503 }
1504
1505
1506 template <int dim, int spacedim>
1507 int
1508 PartitionWeights<dim, spacedim>::cell_weight(
1509 typename internal::p4est::types<dim>::forest *forest,
1512 {
1513 // the function gets two additional arguments, but we don't need them
1514 // since we know in which order p4est will walk through the cells
1515 // and have already built our weight lists in this order
1516
1517 PartitionWeights<dim, spacedim> *this_object =
1518 reinterpret_cast<PartitionWeights<dim, spacedim> *>(forest->user_pointer);
1519
1520 Assert(this_object->current_pointer >=
1521 this_object->cell_weights_list.begin(),
1523 Assert(this_object->current_pointer < this_object->cell_weights_list.end(),
1525
1526 // Get the weight, increment the pointer, and return the weight. Also
1527 // make sure that we don't exceed the 'int' data type that p4est uses
1528 // to represent weights
1529 const unsigned int weight = *this_object->current_pointer;
1530 ++this_object->current_pointer;
1531
1532 Assert(weight < static_cast<unsigned int>(std::numeric_limits<int>::max()),
1533 ExcMessage("p4est uses 'signed int' to represent the partition "
1534 "weights for cells. The weight provided here exceeds "
1535 "the maximum value represented as a 'signed int'."));
1536 return static_cast<int>(weight);
1537 }
1538
1539 template <int dim, int spacedim>
1540 using cell_relation_t = typename std::pair<
1541 typename ::Triangulation<dim, spacedim>::cell_iterator,
1542 CellStatus>;
1543
1553 template <int dim, int spacedim>
1554 void
1555 add_single_cell_relation(
1556 std::vector<cell_relation_t<dim, spacedim>> &cell_rel,
1557 const typename ::internal::p4est::types<dim>::tree &tree,
1558 const unsigned int idx,
1559 const typename Triangulation<dim, spacedim>::cell_iterator &dealii_cell,
1560 const CellStatus status)
1561 {
1562 const unsigned int local_quadrant_index = tree.quadrants_offset + idx;
1563
1564 // check if we will be writing into valid memory
1565 Assert(local_quadrant_index < cell_rel.size(), ExcInternalError());
1566
1567 // store relation
1568 cell_rel[local_quadrant_index] = std::make_pair(dealii_cell, status);
1569 }
1570
1571
1572
1582 template <int dim, int spacedim>
1583 void
1584 update_cell_relations_recursively(
1585 std::vector<cell_relation_t<dim, spacedim>> &cell_rel,
1586 const typename ::internal::p4est::types<dim>::tree &tree,
1587 const typename Triangulation<dim, spacedim>::cell_iterator &dealii_cell,
1588 const typename ::internal::p4est::types<dim>::quadrant &p4est_cell)
1589 {
1590 // find index of p4est_cell in the quadrants array of the corresponding tree
1591 const int idx = sc_array_bsearch(
1592 const_cast<sc_array_t *>(&tree.quadrants),
1593 &p4est_cell,
1595 if (idx == -1 &&
1597 const_cast<typename ::internal::p4est::types<dim>::tree *>(
1598 &tree),
1599 &p4est_cell) == false))
1600 // this quadrant and none of its children belong to us.
1601 return;
1602
1603 // recurse further if both p4est and dealii still have children
1604 const bool p4est_has_children = (idx == -1);
1605 if (p4est_has_children && dealii_cell->has_children())
1606 {
1607 // recurse further
1608 typename ::internal::p4est::types<dim>::quadrant
1610
1611 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1612 ++c)
1614
1616 &p4est_cell, p4est_child);
1617
1618 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1619 ++c)
1620 {
1621 update_cell_relations_recursively<dim, spacedim>(
1622 cell_rel, tree, dealii_cell->child(c), p4est_child[c]);
1623 }
1624 }
1625 else if (!p4est_has_children && !dealii_cell->has_children())
1626 {
1627 // this active cell didn't change
1628 // save pair into corresponding position
1629 add_single_cell_relation<dim, spacedim>(
1630 cell_rel, tree, idx, dealii_cell, CellStatus::cell_will_persist);
1631 }
1632 else if (p4est_has_children) // based on the conditions above, we know that
1633 // dealii_cell has no children
1634 {
1635 // this cell got refined in p4est, but the dealii_cell has not yet been
1636 // refined
1637
1638 // this quadrant is not active
1639 // generate its children, and store information in those
1640 typename ::internal::p4est::types<dim>::quadrant
1642 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1643 ++c)
1645
1647 &p4est_cell, p4est_child);
1648
1649 // mark first child with CellStatus::cell_will_be_refined and the
1650 // remaining children with CellStatus::cell_invalid, but associate them
1651 // all with the parent cell unpack algorithm will be called only on
1652 // CellStatus::cell_will_be_refined flagged quadrant
1653 int child_idx;
1654 CellStatus cell_status;
1655 for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_cell;
1656 ++i)
1657 {
1658 child_idx = sc_array_bsearch(
1659 const_cast<sc_array_t *>(&tree.quadrants),
1660 &p4est_child[i],
1662
1663 cell_status = (i == 0) ? CellStatus::cell_will_be_refined :
1665
1666 add_single_cell_relation<dim, spacedim>(
1667 cell_rel, tree, child_idx, dealii_cell, cell_status);
1668 }
1669 }
1670 else // based on the conditions above, we know that p4est_cell has no
1671 // children, and the dealii_cell does
1672 {
1673 // its children got coarsened into this cell in p4est,
1674 // but the dealii_cell still has its children
1675 add_single_cell_relation<dim, spacedim>(
1676 cell_rel,
1677 tree,
1678 idx,
1679 dealii_cell,
1681 }
1682 }
1683} // namespace
1684
1685
1686
1687namespace parallel
1688{
1689 namespace distributed
1690 {
1691 /*----------------- class Triangulation<dim,spacedim> ---------------*/
1692 template <int dim, int spacedim>
1695 const MPI_Comm mpi_communicator,
1696 const typename ::Triangulation<dim, spacedim>::MeshSmoothing
1697 smooth_grid,
1698 const Settings settings)
1699 : // Do not check for distorted cells.
1700 // For multigrid, we need limit_level_difference_at_vertices
1701 // to make sure the transfer operators only need to consider two levels.
1702 ::parallel::DistributedTriangulationBase<dim, spacedim>(
1703 mpi_communicator,
1704 (settings & construct_multigrid_hierarchy) ?
1705 static_cast<
1706 typename ::Triangulation<dim, spacedim>::MeshSmoothing>(
1707 smooth_grid |
1708 Triangulation<dim, spacedim>::limit_level_difference_at_vertices) :
1709 smooth_grid,
1710 false)
1711 , settings(settings)
1712 , triangulation_has_content(false)
1713 , connectivity(nullptr)
1714 , parallel_forest(nullptr)
1715 {
1716 parallel_ghost = nullptr;
1717 }
1718
1719
1720
1721 template <int dim, int spacedim>
1723 Triangulation<dim, spacedim>::~Triangulation()
1724 {
1725 try
1726 {
1727 // Calling virtual functions in constructors and destructors
1728 // is not entirely intuitive and may not result in what one
1729 // expects. For clarity be explicit on which function is
1730 // called:
1732 }
1733 catch (...)
1734 {}
1735
1736 AssertNothrow(triangulation_has_content == false, ExcInternalError());
1737 AssertNothrow(connectivity == nullptr, ExcInternalError());
1738 AssertNothrow(parallel_forest == nullptr, ExcInternalError());
1739 }
1740
1741
1742
1743 template <int dim, int spacedim>
1745 void Triangulation<dim, spacedim>::create_triangulation(
1746 const std::vector<Point<spacedim>> &vertices,
1747 const std::vector<CellData<dim>> &cells,
1748 const SubCellData &subcelldata)
1749 {
1750 try
1751 {
1753 vertices, cells, subcelldata);
1754 }
1755 catch (
1756 const typename ::Triangulation<dim, spacedim>::DistortedCellList
1757 &)
1758 {
1759 // the underlying triangulation should not be checking for distorted
1760 // cells
1762 }
1763
1764 Assert(
1765 this->all_reference_cells_are_hyper_cube(),
1766 ExcMessage(
1767 "The class parallel::distributed::Triangulation only supports meshes "
1768 "consisting only of hypercube-like cells."));
1769
1770 // note that now we have some content in the p4est objects and call the
1771 // functions that do the actual work (which are dimension dependent, so
1772 // separate)
1773 triangulation_has_content = true;
1774
1775 setup_coarse_cell_to_p4est_tree_permutation();
1776
1777 copy_new_triangulation_to_p4est(std::integral_constant<int, dim>());
1778
1779 try
1780 {
1781 copy_local_forest_to_triangulation();
1782 }
1783 catch (const typename Triangulation<dim>::DistortedCellList &)
1784 {
1785 // the underlying triangulation should not be checking for distorted
1786 // cells
1788 }
1789
1790 this->update_periodic_face_map();
1791 this->update_number_cache();
1792 }
1793
1794
1795
1796 template <int dim, int spacedim>
1798 void Triangulation<dim, spacedim>::create_triangulation(
1799 const TriangulationDescription::Description<dim, spacedim>
1800 & /*construction_data*/)
1801 {
1803 }
1804
1805
1806
1807 template <int dim, int spacedim>
1809 void Triangulation<dim, spacedim>::clear()
1810 {
1811 triangulation_has_content = false;
1812
1813 if (parallel_ghost != nullptr)
1814 {
1816 parallel_ghost);
1817 parallel_ghost = nullptr;
1818 }
1819
1820 if (parallel_forest != nullptr)
1821 {
1823 parallel_forest = nullptr;
1824 }
1825
1826 if (connectivity != nullptr)
1827 {
1829 connectivity);
1830 connectivity = nullptr;
1831 }
1832
1833 coarse_cell_to_p4est_tree_permutation.resize(0);
1834 p4est_tree_to_coarse_cell_permutation.resize(0);
1835
1837
1838 this->update_number_cache();
1839 }
1840
1841
1842
1843 template <int dim, int spacedim>
1845 bool Triangulation<dim, spacedim>::is_multilevel_hierarchy_constructed()
1846 const
1847 {
1848 return settings &
1850 }
1851
1852
1853
1854 template <int dim, int spacedim>
1856 bool Triangulation<dim, spacedim>::are_vertices_communicated_to_p4est()
1857 const
1858 {
1859 return settings &
1861 }
1862
1863
1864
1865 template <int dim, int spacedim>
1867 void Triangulation<dim, spacedim>::execute_transfer(
1868 const typename ::internal::p4est::types<dim>::forest
1869 *parallel_forest,
1870 const typename ::internal::p4est::types<dim>::gloidx
1871 *previous_global_first_quadrant)
1872 {
1873 Assert(this->data_serializer.sizes_fixed_cumulative.size() > 0,
1874 ExcMessage("No data has been packed!"));
1875
1876 // Resize memory according to the data that we will receive.
1877 this->data_serializer.dest_data_fixed.resize(
1878 parallel_forest->local_num_quadrants *
1879 this->data_serializer.sizes_fixed_cumulative.back());
1880
1881 // Execute non-blocking fixed size transfer.
1882 typename ::internal::p4est::types<dim>::transfer_context
1883 *tf_context;
1884 tf_context =
1886 parallel_forest->global_first_quadrant,
1887 previous_global_first_quadrant,
1888 parallel_forest->mpicomm,
1889 0,
1890 this->data_serializer.dest_data_fixed.data(),
1891 this->data_serializer.src_data_fixed.data(),
1892 this->data_serializer.sizes_fixed_cumulative.back());
1893
1894 if (this->data_serializer.variable_size_data_stored)
1895 {
1896 // Resize memory according to the data that we will receive.
1897 this->data_serializer.dest_sizes_variable.resize(
1898 parallel_forest->local_num_quadrants);
1899
1900 // Execute fixed size transfer of data sizes for variable size
1901 // transfer.
1903 parallel_forest->global_first_quadrant,
1904 previous_global_first_quadrant,
1905 parallel_forest->mpicomm,
1906 1,
1907 this->data_serializer.dest_sizes_variable.data(),
1908 this->data_serializer.src_sizes_variable.data(),
1909 sizeof(unsigned int));
1910 }
1911
1913
1914 // Release memory of previously packed data.
1915 this->data_serializer.src_data_fixed.clear();
1916 this->data_serializer.src_data_fixed.shrink_to_fit();
1917
1918 if (this->data_serializer.variable_size_data_stored)
1919 {
1920 // Resize memory according to the data that we will receive.
1921 this->data_serializer.dest_data_variable.resize(
1922 std::accumulate(this->data_serializer.dest_sizes_variable.begin(),
1923 this->data_serializer.dest_sizes_variable.end(),
1924 std::vector<int>::size_type(0)));
1925
1926 // Execute variable size transfer.
1928 parallel_forest->global_first_quadrant,
1929 previous_global_first_quadrant,
1930 parallel_forest->mpicomm,
1931 1,
1932 this->data_serializer.dest_data_variable.data(),
1933 this->data_serializer.dest_sizes_variable.data(),
1934 this->data_serializer.src_data_variable.data(),
1935 this->data_serializer.src_sizes_variable.data());
1936
1937 // Release memory of previously packed data.
1938 this->data_serializer.src_sizes_variable.clear();
1939 this->data_serializer.src_sizes_variable.shrink_to_fit();
1940 this->data_serializer.src_data_variable.clear();
1941 this->data_serializer.src_data_variable.shrink_to_fit();
1942 }
1943 }
1944
1945
1946
1947 template <int dim, int spacedim>
1949 void Triangulation<dim,
1950 spacedim>::setup_coarse_cell_to_p4est_tree_permutation()
1951 {
1952 DynamicSparsityPattern cell_connectivity;
1954 cell_connectivity);
1955 coarse_cell_to_p4est_tree_permutation.resize(this->n_cells(0));
1957 cell_connectivity, coarse_cell_to_p4est_tree_permutation);
1958
1959 p4est_tree_to_coarse_cell_permutation =
1960 Utilities::invert_permutation(coarse_cell_to_p4est_tree_permutation);
1961 }
1962
1963
1964
1965 template <int dim, int spacedim>
1967 void Triangulation<dim, spacedim>::write_mesh_vtk(
1968 const std::string &file_basename) const
1969 {
1970 Assert(parallel_forest != nullptr,
1971 ExcMessage("Can't produce output when no forest is created yet."));
1972
1973 AssertThrow(are_vertices_communicated_to_p4est(),
1974 ExcMessage(
1975 "To use this function the triangulation's flag "
1976 "Settings::communicate_vertices_to_p4est must be set."));
1977
1979 parallel_forest, nullptr, file_basename.c_str());
1980 }
1981
1982
1983
1984 template <int dim, int spacedim>
1986 void Triangulation<dim, spacedim>::save(
1987 const std::string &file_basename) const
1988 {
1989 Assert(
1990 this->cell_attached_data.n_attached_deserialize == 0,
1991 ExcMessage(
1992 "Not all SolutionTransfer objects have been deserialized after the last call to load()."));
1993 Assert(this->n_cells() > 0,
1994 ExcMessage("Can not save() an empty Triangulation."));
1995
1996 const int myrank =
1997 Utilities::MPI::this_mpi_process(this->mpi_communicator);
1998
1999 // signal that serialization is going to happen
2000 this->signals.pre_distributed_save();
2001
2002 if (this->my_subdomain == 0)
2003 {
2004 std::string fname = file_basename + ".info";
2005 std::ofstream f(fname);
2006 f << "version nproc n_attached_fixed_size_objs n_attached_variable_size_objs n_coarse_cells"
2007 << std::endl
2008 << 5 << " "
2009 << Utilities::MPI::n_mpi_processes(this->mpi_communicator) << " "
2010 << this->cell_attached_data.pack_callbacks_fixed.size() << " "
2011 << this->cell_attached_data.pack_callbacks_variable.size() << " "
2012 << this->n_cells(0) << std::endl;
2013 }
2014
2015 // each cell should have been flagged `CellStatus::cell_will_persist`
2016 for ([[maybe_unused]] const auto &cell_rel : this->local_cell_relations)
2017 {
2018 Assert((cell_rel.second == // cell_status
2021 }
2022
2023 // Save cell attached data.
2024 this->save_attached_data(parallel_forest->global_first_quadrant[myrank],
2025 parallel_forest->global_num_quadrants,
2026 file_basename);
2027
2028 ::internal::p4est::functions<dim>::save(file_basename.c_str(),
2029 parallel_forest,
2030 false);
2031
2032 // signal that serialization has finished
2033 this->signals.post_distributed_save();
2034 }
2035
2036
2037
2038 template <int dim, int spacedim>
2040 void Triangulation<dim, spacedim>::load(const std::string &file_basename)
2041 {
2042 Assert(
2043 this->n_cells() > 0,
2044 ExcMessage(
2045 "load() only works if the Triangulation already contains a coarse mesh!"));
2046 Assert(
2047 this->n_levels() == 1,
2048 ExcMessage(
2049 "Triangulation may only contain coarse cells when calling load()."));
2050
2051 const int myrank =
2052 Utilities::MPI::this_mpi_process(this->mpi_communicator);
2053
2054 // signal that de-serialization is going to happen
2055 this->signals.pre_distributed_load();
2056
2057 if (parallel_ghost != nullptr)
2058 {
2060 parallel_ghost);
2061 parallel_ghost = nullptr;
2062 }
2064 parallel_forest = nullptr;
2066 connectivity);
2067 connectivity = nullptr;
2068
2069 unsigned int version, numcpus, attached_count_fixed,
2070 attached_count_variable, n_coarse_cells;
2071 {
2072 std::string fname = std::string(file_basename) + ".info";
2073 std::ifstream f(fname);
2074 AssertThrow(f.fail() == false, ExcIO());
2075 std::string firstline;
2076 getline(f, firstline); // skip first line
2077 f >> version >> numcpus >> attached_count_fixed >>
2078 attached_count_variable >> n_coarse_cells;
2079 }
2080
2081 AssertThrow(version == 5,
2082 ExcMessage("Incompatible version found in .info file."));
2083 Assert(this->n_cells(0) == n_coarse_cells,
2084 ExcMessage("Number of coarse cells differ!"));
2085
2086 // clear all of the callback data, as explained in the documentation of
2087 // register_data_attach()
2088 this->cell_attached_data.n_attached_data_sets = 0;
2089 this->cell_attached_data.n_attached_deserialize =
2090 attached_count_fixed + attached_count_variable;
2091
2093 file_basename.c_str(),
2094 this->mpi_communicator,
2095 0,
2096 0,
2097 1,
2098 0,
2099 this,
2100 &connectivity);
2101
2102 // We partition the p4est mesh that it conforms to the requirements of the
2103 // deal.II mesh, i.e., partition for coarsening.
2104 // This function call is optional.
2106 parallel_forest,
2107 /* prepare coarsening */ 1,
2108 /* weight_callback */ nullptr);
2109
2110 try
2111 {
2112 copy_local_forest_to_triangulation();
2113 }
2114 catch (const typename Triangulation<dim>::DistortedCellList &)
2115 {
2116 // the underlying triangulation should not be checking for distorted
2117 // cells
2119 }
2120
2121 // Load attached cell data, if any was stored.
2122 this->load_attached_data(parallel_forest->global_first_quadrant[myrank],
2123 parallel_forest->global_num_quadrants,
2124 parallel_forest->local_num_quadrants,
2125 file_basename,
2126 attached_count_fixed,
2127 attached_count_variable);
2128
2129 // signal that de-serialization is finished
2130 this->signals.post_distributed_load();
2131
2132 this->update_periodic_face_map();
2133 this->update_number_cache();
2134 }
2135
2136
2137
2138 template <int dim, int spacedim>
2140 void Triangulation<dim, spacedim>::load(
2141 const typename ::internal::p4est::types<dim>::forest *forest)
2142 {
2143 Assert(this->n_cells() > 0,
2144 ExcMessage(
2145 "load() only works if the Triangulation already contains "
2146 "a coarse mesh!"));
2147 Assert(this->n_cells() == forest->trees->elem_count,
2148 ExcMessage(
2149 "Coarse mesh of the Triangulation does not match the one "
2150 "of the provided forest!"));
2151
2152 // clear the old forest
2153 if (parallel_ghost != nullptr)
2154 {
2156 parallel_ghost);
2157 parallel_ghost = nullptr;
2158 }
2160 parallel_forest = nullptr;
2161
2162 // note: we can keep the connectivity, since the coarse grid does not
2163 // change
2164
2165 // create deep copy of the new forest
2166 typename ::internal::p4est::types<dim>::forest *temp =
2167 const_cast<typename ::internal::p4est::types<dim>::forest *>(
2168 forest);
2169 parallel_forest =
2171 parallel_forest->connectivity = connectivity;
2172 parallel_forest->user_pointer = this;
2173
2174 try
2175 {
2176 copy_local_forest_to_triangulation();
2177 }
2178 catch (const typename Triangulation<dim>::DistortedCellList &)
2179 {
2180 // the underlying triangulation should not be checking for distorted
2181 // cells
2183 }
2184
2185 this->update_periodic_face_map();
2186 this->update_number_cache();
2187 }
2188
2189
2190
2191 template <int dim, int spacedim>
2193 unsigned int Triangulation<dim, spacedim>::get_checksum() const
2194 {
2195 Assert(parallel_forest != nullptr,
2196 ExcMessage(
2197 "Can't produce a check sum when no forest is created yet."));
2198
2199 auto checksum =
2201
2202# if !DEAL_II_P4EST_VERSION_GTE(2, 8, 6, 0)
2203 /*
2204 * p4est prior to 2.8.6 returns the proper checksum only on rank 0
2205 * and simply "0" on all other ranks. This is not really what we
2206 * want, thus broadcast the correct value to all other ranks:
2207 */
2208 checksum = Utilities::MPI::broadcast(this->mpi_communicator,
2209 checksum,
2210 /*root_process*/ 0);
2211# endif
2212
2213 return checksum;
2214 }
2215
2216
2217
2218 template <int dim, int spacedim>
2220 const typename ::internal::p4est::types<dim>::forest
2222 {
2223 Assert(parallel_forest != nullptr,
2224 ExcMessage("The forest has not been allocated yet."));
2225 return parallel_forest;
2226 }
2227
2228
2229
2230 template <int dim, int spacedim>
2232 typename ::internal::p4est::types<dim>::tree
2234 const int dealii_coarse_cell_index) const
2235 {
2236 const unsigned int tree_index =
2237 coarse_cell_to_p4est_tree_permutation[dealii_coarse_cell_index];
2238 typename ::internal::p4est::types<dim>::tree *tree =
2239 static_cast<typename ::internal::p4est::types<dim>::tree *>(
2240 sc_array_index(parallel_forest->trees, tree_index));
2241
2242 return tree;
2243 }
2244
2245
2246
2247 // Note: this has been added here to prevent that these functions
2248 // appear in the Doxygen documentation of ::Triangulation
2249# ifndef DOXYGEN
2250
2251 template <>
2252 void
2254 std::integral_constant<int, 2>)
2255 {
2256 const unsigned int dim = 2, spacedim = 2;
2257 Assert(this->n_cells(0) > 0, ExcInternalError());
2258 Assert(this->n_levels() == 1, ExcInternalError());
2259
2260 // data structures that counts how many cells touch each vertex
2261 // (vertex_touch_count), and which cells touch a given vertex (together
2262 // with the local numbering of that vertex within the cells that touch
2263 // it)
2264 std::vector<unsigned int> vertex_touch_count;
2265 std::vector<
2266 std::list<std::pair<Triangulation<dim, spacedim>::active_cell_iterator,
2267 unsigned int>>>
2268 vertex_to_cell;
2269 get_vertex_to_cell_mappings(*this, vertex_touch_count, vertex_to_cell);
2270 const ::internal::p4est::types<2>::locidx num_vtt =
2271 std::accumulate(vertex_touch_count.begin(),
2272 vertex_touch_count.end(),
2273 0u);
2274
2275 // now create a connectivity object with the right sizes for all
2276 // arrays. set vertex information only in debug mode (saves a few bytes
2277 // in optimized mode)
2278 const bool set_vertex_info = this->are_vertices_communicated_to_p4est();
2279
2281 (set_vertex_info == true ? this->n_vertices() : 0),
2282 this->n_cells(0),
2283 this->n_vertices(),
2284 num_vtt);
2285
2286 set_vertex_and_cell_info(*this,
2287 vertex_touch_count,
2288 vertex_to_cell,
2289 coarse_cell_to_p4est_tree_permutation,
2290 set_vertex_info,
2291 connectivity);
2292
2293 Assert(p4est_connectivity_is_valid(connectivity) == 1,
2295
2296 // now create a forest out of the connectivity data structure
2298 this->mpi_communicator,
2299 connectivity,
2300 /* minimum initial number of quadrants per tree */ 0,
2301 /* minimum level of upfront refinement */ 0,
2302 /* use uniform upfront refinement */ 1,
2303 /* user_data_size = */ 0,
2304 /* user_data_constructor = */ nullptr,
2305 /* user_pointer */ this);
2306 }
2307
2308
2309
2310 // TODO: This is a verbatim copy of the 2,2 case. However, we can't just
2311 // specialize the dim template argument, but let spacedim open
2312 template <>
2313 void
2315 std::integral_constant<int, 2>)
2316 {
2317 const unsigned int dim = 2, spacedim = 3;
2318 Assert(this->n_cells(0) > 0, ExcInternalError());
2319 Assert(this->n_levels() == 1, ExcInternalError());
2320
2321 // data structures that counts how many cells touch each vertex
2322 // (vertex_touch_count), and which cells touch a given vertex (together
2323 // with the local numbering of that vertex within the cells that touch
2324 // it)
2325 std::vector<unsigned int> vertex_touch_count;
2326 std::vector<
2327 std::list<std::pair<Triangulation<dim, spacedim>::active_cell_iterator,
2328 unsigned int>>>
2329 vertex_to_cell;
2330 get_vertex_to_cell_mappings(*this, vertex_touch_count, vertex_to_cell);
2331 const ::internal::p4est::types<2>::locidx num_vtt =
2332 std::accumulate(vertex_touch_count.begin(),
2333 vertex_touch_count.end(),
2334 0u);
2335
2336 // now create a connectivity object with the right sizes for all
2337 // arrays. set vertex information only in debug mode (saves a few bytes
2338 // in optimized mode)
2339 const bool set_vertex_info = this->are_vertices_communicated_to_p4est();
2340
2342 (set_vertex_info == true ? this->n_vertices() : 0),
2343 this->n_cells(0),
2344 this->n_vertices(),
2345 num_vtt);
2346
2347 set_vertex_and_cell_info(*this,
2348 vertex_touch_count,
2349 vertex_to_cell,
2350 coarse_cell_to_p4est_tree_permutation,
2351 set_vertex_info,
2352 connectivity);
2353
2354 Assert(p4est_connectivity_is_valid(connectivity) == 1,
2356
2357 // now create a forest out of the connectivity data structure
2359 this->mpi_communicator,
2360 connectivity,
2361 /* minimum initial number of quadrants per tree */ 0,
2362 /* minimum level of upfront refinement */ 0,
2363 /* use uniform upfront refinement */ 1,
2364 /* user_data_size = */ 0,
2365 /* user_data_constructor = */ nullptr,
2366 /* user_pointer */ this);
2367 }
2368
2369
2370
2371 template <>
2372 void
2374 std::integral_constant<int, 3>)
2375 {
2376 const int dim = 3, spacedim = 3;
2377 Assert(this->n_cells(0) > 0, ExcInternalError());
2378 Assert(this->n_levels() == 1, ExcInternalError());
2379
2380 // data structures that counts how many cells touch each vertex
2381 // (vertex_touch_count), and which cells touch a given vertex (together
2382 // with the local numbering of that vertex within the cells that touch
2383 // it)
2384 std::vector<unsigned int> vertex_touch_count;
2385 std::vector<std::list<
2386 std::pair<Triangulation<3>::active_cell_iterator, unsigned int>>>
2387 vertex_to_cell;
2388 get_vertex_to_cell_mappings(*this, vertex_touch_count, vertex_to_cell);
2389 const ::internal::p4est::types<2>::locidx num_vtt =
2390 std::accumulate(vertex_touch_count.begin(),
2391 vertex_touch_count.end(),
2392 0u);
2393
2394 std::vector<unsigned int> edge_touch_count;
2395 std::vector<std::list<
2396 std::pair<Triangulation<3>::active_cell_iterator, unsigned int>>>
2397 edge_to_cell;
2398 get_edge_to_cell_mappings(*this, edge_touch_count, edge_to_cell);
2399 const ::internal::p4est::types<2>::locidx num_ett =
2400 std::accumulate(edge_touch_count.begin(), edge_touch_count.end(), 0u);
2401
2402 // now create a connectivity object with the right sizes for all arrays
2403 const bool set_vertex_info = this->are_vertices_communicated_to_p4est();
2404
2406 (set_vertex_info == true ? this->n_vertices() : 0),
2407 this->n_cells(0),
2408 this->n_active_lines(),
2409 num_ett,
2410 this->n_vertices(),
2411 num_vtt);
2412
2413 set_vertex_and_cell_info(*this,
2414 vertex_touch_count,
2415 vertex_to_cell,
2416 coarse_cell_to_p4est_tree_permutation,
2417 set_vertex_info,
2418 connectivity);
2419
2420 // next to tree-to-edge
2421 // data. note that in p4est lines
2422 // are ordered as follows
2423 // *---3---* *---3---*
2424 // /| | / /|
2425 // 6 | 11 6 7 11
2426 // / 10 | / / |
2427 // * | | *---2---* |
2428 // | *---1---* | | *
2429 // | / / | 9 /
2430 // 8 4 5 8 | 5
2431 // |/ / | |/
2432 // *---0---* *---0---*
2433 // whereas in deal.II they are like this:
2434 // *---7---* *---7---*
2435 // /| | / /|
2436 // 4 | 11 4 5 11
2437 // / 10 | / / |
2438 // * | | *---6---* |
2439 // | *---3---* | | *
2440 // | / / | 9 /
2441 // 8 0 1 8 | 1
2442 // |/ / | |/
2443 // *---2---* *---2---*
2444
2445 const unsigned int deal_to_p4est_line_index[12] = {
2446 4, 5, 0, 1, 6, 7, 2, 3, 8, 9, 10, 11};
2447
2448 for (const auto &cell : this->active_cell_iterators())
2449 {
2450 const unsigned int index =
2451 coarse_cell_to_p4est_tree_permutation[cell->index()];
2452 for (unsigned int e = 0; e < cell->n_lines(); ++e)
2453 connectivity->tree_to_edge[index * GeometryInfo<3>::lines_per_cell +
2454 deal_to_p4est_line_index[e]] =
2455 cell->line(e)->index();
2456 }
2457
2458 // now also set edge-to-tree
2459 // information
2460 connectivity->ett_offset[0] = 0;
2461 std::partial_sum(edge_touch_count.begin(),
2462 edge_touch_count.end(),
2463 &connectivity->ett_offset[1]);
2464
2465 Assert(connectivity->ett_offset[this->n_active_lines()] == num_ett,
2467
2468 for (unsigned int v = 0; v < this->n_active_lines(); ++v)
2469 {
2470 Assert(edge_to_cell[v].size() == edge_touch_count[v],
2472
2473 std::list<
2474 std::pair<Triangulation<dim, spacedim>::active_cell_iterator,
2475 unsigned int>>::const_iterator p =
2476 edge_to_cell[v].begin();
2477 for (unsigned int c = 0; c < edge_touch_count[v]; ++c, ++p)
2478 {
2479 connectivity->edge_to_tree[connectivity->ett_offset[v] + c] =
2480 coarse_cell_to_p4est_tree_permutation[p->first->index()];
2481 connectivity->edge_to_edge[connectivity->ett_offset[v] + c] =
2482 deal_to_p4est_line_index[p->second];
2483 }
2484 }
2485
2486 Assert(p8est_connectivity_is_valid(connectivity) == 1,
2488
2489 // now create a forest out of the connectivity data structure
2491 this->mpi_communicator,
2492 connectivity,
2493 /* minimum initial number of quadrants per tree */ 0,
2494 /* minimum level of upfront refinement */ 0,
2495 /* use uniform upfront refinement */ 1,
2496 /* user_data_size = */ 0,
2497 /* user_data_constructor = */ nullptr,
2498 /* user_pointer */ this);
2499 }
2500# endif
2501
2502
2503
2504 namespace
2505 {
2506 // ensures the 2:1 mesh balance for periodic boundary conditions in the
2507 // artificial cell layer (the active cells are taken care of by p4est)
2508 template <int dim, int spacedim>
2509 bool
2510 enforce_mesh_balance_over_periodic_boundaries(
2512 {
2513 if (tria.get_periodic_face_map().empty())
2514 return false;
2515
2516 std::vector<bool> flags_before[2];
2517 tria.save_coarsen_flags(flags_before[0]);
2518 tria.save_refine_flags(flags_before[1]);
2519
2520 std::vector<unsigned int> topological_vertex_numbering(
2521 tria.n_vertices());
2522 for (unsigned int i = 0; i < topological_vertex_numbering.size(); ++i)
2523 topological_vertex_numbering[i] = i;
2524 // combine vertices that have different locations (and thus, different
2525 // vertex_index) but represent the same topological entity over
2526 // periodic boundaries. The vector topological_vertex_numbering
2527 // contains a linear map from 0 to n_vertices at input and at output
2528 // relates periodic vertices with only one vertex index. The output is
2529 // used to always identify the same vertex according to the
2530 // periodicity, e.g. when finding the maximum cell level around a
2531 // vertex.
2532 //
2533 // Example: On a 3d cell with vertices numbered from 0 to 7 and
2534 // periodic boundary conditions in x direction, the vector
2535 // topological_vertex_numbering will contain the numbers
2536 // {0,0,2,2,4,4,6,6} (because the vertex pairs {0,1}, {2,3}, {4,5},
2537 // {6,7} belong together, respectively). If periodicity is set in x
2538 // and z direction, the output is {0,0,2,2,0,0,2,2}, and if
2539 // periodicity is in all directions, the output is simply
2540 // {0,0,0,0,0,0,0,0}.
2541 using cell_iterator =
2543 for (const auto &it : tria.get_periodic_face_map())
2544 {
2545 const cell_iterator &cell_1 = it.first.first;
2546 const unsigned int face_no_1 = it.first.second;
2547 const cell_iterator &cell_2 = it.second.first.first;
2548 const unsigned int face_no_2 = it.second.first.second;
2549 const auto combined_orientation = it.second.second;
2550
2551 if (cell_1->level() == cell_2->level())
2552 {
2553 for (const unsigned int v :
2554 cell_1->face(face_no_1)->vertex_indices())
2555 {
2556 // take possible non-standard orientation of face on
2557 // cell[0] into account
2558 const unsigned int vface1 =
2559 cell_1->reference_cell().standard_to_real_face_vertex(
2560 v, face_no_1, combined_orientation);
2561 const unsigned int vi1 =
2562 topological_vertex_numbering[cell_1->face(face_no_1)
2563 ->vertex_index(vface1)];
2564 const unsigned int vi2 =
2565 topological_vertex_numbering[cell_2->face(face_no_2)
2566 ->vertex_index(v)];
2567 const unsigned int min_index = std::min(vi1, vi2);
2568 topological_vertex_numbering[cell_1->face(face_no_1)
2569 ->vertex_index(vface1)] =
2570 topological_vertex_numbering[cell_2->face(face_no_2)
2571 ->vertex_index(v)] =
2572 min_index;
2573 }
2574 }
2575 }
2576
2577 if constexpr (running_in_debug_mode())
2578 {
2579 // There must not be any chains!
2580 for (unsigned int i = 0; i < topological_vertex_numbering.size();
2581 ++i)
2582 {
2583 const unsigned int j = topological_vertex_numbering[i];
2584 Assert(j == i || topological_vertex_numbering[j] == j,
2585 ExcMessage(
2586 "Got inconclusive constraints with chain: " +
2587 std::to_string(i) + " vs " + std::to_string(j) +
2588 " which should be equal to " +
2589 std::to_string(topological_vertex_numbering[j])));
2590 }
2591 }
2592
2593
2594 // this code is replicated from grid/tria.cc but using an indirection
2595 // for periodic boundary conditions
2596 bool continue_iterating = true;
2597 std::vector<int> vertex_level(tria.n_vertices());
2598 while (continue_iterating)
2599 {
2600 // store highest level one of the cells adjacent to a vertex
2601 // belongs to
2602 std::fill(vertex_level.begin(), vertex_level.end(), 0);
2604 cell = tria.begin_active(),
2605 endc = tria.end();
2606 for (; cell != endc; ++cell)
2607 {
2608 if (cell->refine_flag_set())
2609 for (const unsigned int vertex :
2611 vertex_level[topological_vertex_numbering
2612 [cell->vertex_index(vertex)]] =
2613 std::max(vertex_level[topological_vertex_numbering
2614 [cell->vertex_index(vertex)]],
2615 cell->level() + 1);
2616 else if (!cell->coarsen_flag_set())
2617 for (const unsigned int vertex :
2619 vertex_level[topological_vertex_numbering
2620 [cell->vertex_index(vertex)]] =
2621 std::max(vertex_level[topological_vertex_numbering
2622 [cell->vertex_index(vertex)]],
2623 cell->level());
2624 else
2625 {
2626 // if coarsen flag is set then tentatively assume
2627 // that the cell will be coarsened. this isn't
2628 // always true (the coarsen flag could be removed
2629 // again) and so we may make an error here. we try
2630 // to correct this by iterating over the entire
2631 // process until we are converged
2632 Assert(cell->coarsen_flag_set(), ExcInternalError());
2633 for (const unsigned int vertex :
2635 vertex_level[topological_vertex_numbering
2636 [cell->vertex_index(vertex)]] =
2637 std::max(vertex_level[topological_vertex_numbering
2638 [cell->vertex_index(vertex)]],
2639 cell->level() - 1);
2640 }
2641 }
2642
2643 continue_iterating = false;
2644
2645 // loop over all cells in reverse order. do so because we
2646 // can then update the vertex levels on the adjacent
2647 // vertices and maybe already flag additional cells in this
2648 // loop
2649 //
2650 // note that not only may we have to add additional
2651 // refinement flags, but we will also have to remove
2652 // coarsening flags on cells adjacent to vertices that will
2653 // see refinement
2654 for (cell = tria.last_active(); cell != endc; --cell)
2655 if (cell->refine_flag_set() == false)
2656 {
2657 for (const unsigned int vertex :
2659 if (vertex_level[topological_vertex_numbering
2660 [cell->vertex_index(vertex)]] >=
2661 cell->level() + 1)
2662 {
2663 // remove coarsen flag...
2664 cell->clear_coarsen_flag();
2665
2666 // ...and if necessary also refine the current
2667 // cell, at the same time updating the level
2668 // information about vertices
2669 if (vertex_level[topological_vertex_numbering
2670 [cell->vertex_index(vertex)]] >
2671 cell->level() + 1)
2672 {
2673 cell->set_refine_flag();
2674 continue_iterating = true;
2675
2676 for (const unsigned int v :
2678 vertex_level[topological_vertex_numbering
2679 [cell->vertex_index(v)]] =
2680 std::max(
2681 vertex_level[topological_vertex_numbering
2682 [cell->vertex_index(v)]],
2683 cell->level() + 1);
2684 }
2685
2686 // continue and see whether we may, for example,
2687 // go into the inner 'if' above based on a
2688 // different vertex
2689 }
2690 }
2691
2692 // clear coarsen flag if not all children were marked
2693 for (const auto &cell : tria.cell_iterators())
2694 {
2695 // nothing to do if we are already on the finest level
2696 if (cell->is_active())
2697 continue;
2698
2699 const unsigned int n_children = cell->n_children();
2700 unsigned int flagged_children = 0;
2701 for (unsigned int child = 0; child < n_children; ++child)
2702 if (cell->child(child)->is_active() &&
2703 cell->child(child)->coarsen_flag_set())
2704 ++flagged_children;
2705
2706 // if not all children were flagged for coarsening, remove
2707 // coarsen flags
2708 if (flagged_children < n_children)
2709 for (unsigned int child = 0; child < n_children; ++child)
2710 if (cell->child(child)->is_active())
2711 cell->child(child)->clear_coarsen_flag();
2712 }
2713 }
2714 std::vector<bool> flags_after[2];
2715 tria.save_coarsen_flags(flags_after[0]);
2716 tria.save_refine_flags(flags_after[1]);
2717 return ((flags_before[0] != flags_after[0]) ||
2718 (flags_before[1] != flags_after[1]));
2719 }
2720 } // namespace
2721
2722
2723
2724 template <int dim, int spacedim>
2726 bool Triangulation<dim, spacedim>::prepare_coarsening_and_refinement()
2727 {
2728 const bool match_periodic_levels =
2729 this->smooth_grid & ::Triangulation<dim, spacedim>::
2730 match_refinement_across_periodic_boundaries;
2731 const bool has_periodic_faces = !this->get_periodic_face_map().empty();
2732
2733 if (!match_periodic_levels || !has_periodic_faces)
2734 {
2735 // Without handling periodic faces we run a single
2736 // communication step and return.
2739
2742 }
2743
2744 const auto get_locally_owned_flags = [this]() {
2745 std::vector<std::uint8_t> flags;
2746 for (const auto &cell : this->active_cell_iterators())
2747 if (cell->is_locally_owned())
2748 {
2749 flags.push_back(
2750 static_cast<std::uint8_t>(cell->refine_flag_set()));
2751 flags.push_back(cell->coarsen_flag_set() ? 1 : 0);
2752 }
2753 return flags;
2754 };
2755
2756 const std::vector<std::uint8_t> flags_before = get_locally_owned_flags();
2757 bool flags_changed_globally = false;
2758 unsigned int n_iterations = 0;
2759 do
2760 {
2761 AssertThrow(n_iterations <= 10,
2762 ExcMessage(
2763 "The distributed refinement and coarsening flags "
2764 "did not converge after 10 iterations."));
2765
2766 // First get correct flags from the owner of the cells in
2767 // each iteration:
2770
2771 const std::vector<std::uint8_t> flags_before_pass =
2772 get_locally_owned_flags();
2773
2774 // Apply the sequential smoothing algorithms:
2777
2778 const bool flags_changed_locally =
2779 flags_before_pass != get_locally_owned_flags();
2780
2781 flags_changed_globally =
2782 Utilities::MPI::logical_or(flags_changed_locally,
2783 this->get_mpi_communicator());
2784
2785 ++n_iterations;
2786 }
2787 while (flags_changed_globally);
2788
2789 // The sequential pass may have modified ghost copies while applying
2790 // smoothing. Restore the owner values before returning.
2793
2794 return Utilities::MPI::logical_or(flags_before !=
2795 get_locally_owned_flags(),
2796 this->get_mpi_communicator());
2797 }
2798
2799
2800
2801 template <int dim, int spacedim>
2803 void Triangulation<dim, spacedim>::copy_local_forest_to_triangulation()
2804 {
2805 // Disable mesh smoothing for recreating the deal.II triangulation,
2806 // otherwise we might not be able to reproduce the p4est mesh
2807 // exactly. We restore the original smoothing at the end of this
2808 // function. Note that the smoothing flag is used in the normal
2809 // refinement process.
2810 typename Triangulation<dim, spacedim>::MeshSmoothing save_smooth =
2811 this->smooth_grid;
2812
2813 // We will refine manually to match the p4est further down, which
2814 // obeys a level difference of 2 at each vertex (see the balance call
2815 // to p4est). We can disable this here so we store fewer artificial
2816 // cells (in some cases).
2817 // For geometric multigrid it turns out that
2818 // we will miss level cells at shared vertices if we ignore this.
2819 // See tests/mpi/mg_06. In particular, the flag is still necessary
2820 // even though we force it for the original smooth_grid in the
2821 // constructor.
2822 if (settings & construct_multigrid_hierarchy)
2823 this->smooth_grid =
2824 ::Triangulation<dim,
2825 spacedim>::limit_level_difference_at_vertices;
2826 else
2827 this->smooth_grid = ::Triangulation<dim, spacedim>::none;
2828
2829 bool mesh_changed = false;
2830
2831 // Remove all deal.II refinements. Note that we could skip this and
2832 // start from our current state, because the algorithm later coarsens as
2833 // necessary. This has the advantage of being faster when large parts
2834 // of the local partition changes (likely) and gives a deterministic
2835 // ordering of the cells (useful for snapshot/resume).
2836 // TODO: is there a more efficient way to do this?
2837 if (settings & mesh_reconstruction_after_repartitioning)
2838 while (this->n_levels() > 1)
2839 {
2840 // Instead of marking all active cells, we slice off the finest
2841 // level, one level at a time. This takes the same number of
2842 // iterations but solves an issue where not all cells on a
2843 // periodic boundary are indeed coarsened and we run into an
2844 // irrelevant Assert() in update_periodic_face_map().
2845 for (const auto &cell :
2846 this->active_cell_iterators_on_level(this->n_levels() - 1))
2847 {
2848 cell->set_coarsen_flag();
2849 }
2850 try
2851 {
2854 }
2855 catch (
2857 {
2858 // the underlying triangulation should not be checking for
2859 // distorted cells
2861 }
2862 }
2863
2864
2865 // query p4est for the ghost cells
2866 if (parallel_ghost != nullptr)
2867 {
2869 parallel_ghost);
2870 parallel_ghost = nullptr;
2871 }
2873 parallel_forest,
2874 (dim == 2 ? typename ::internal::p4est::types<dim>::balance_type(
2875 P4EST_CONNECT_CORNER) :
2876 typename ::internal::p4est::types<dim>::balance_type(
2877 P8EST_CONNECT_CORNER)));
2878
2879 Assert(parallel_ghost, ExcInternalError());
2880
2881
2882 // set all cells to artificial. we will later set it to the correct
2883 // subdomain in match_tree_recursively
2884 for (const auto &cell : this->cell_iterators_on_level(0))
2885 cell->recursively_set_subdomain_id(numbers::artificial_subdomain_id);
2886
2887 do
2888 {
2889 for (const auto &cell : this->cell_iterators_on_level(0))
2890 {
2891 // if this processor stores no part of the forest that comes out
2892 // of this coarse grid cell, then we need to delete all children
2893 // of this cell (the coarse grid cell remains)
2894 if (tree_exists_locally<dim, spacedim>(
2895 parallel_forest,
2896 coarse_cell_to_p4est_tree_permutation[cell->index()]) ==
2897 false)
2898 {
2899 delete_all_children<dim, spacedim>(cell);
2900 if (cell->is_active())
2901 cell->set_subdomain_id(numbers::artificial_subdomain_id);
2902 }
2903
2904 else
2905 {
2906 // this processor stores at least a part of the tree that
2907 // comes out of this cell.
2908
2909 typename ::internal::p4est::types<dim>::quadrant
2910 p4est_coarse_cell;
2911 typename ::internal::p4est::types<dim>::tree *tree =
2912 init_tree(cell->index());
2913
2914 ::internal::p4est::init_coarse_quadrant<dim>(
2915 p4est_coarse_cell);
2916
2917 match_tree_recursively<dim, spacedim>(*tree,
2918 cell,
2919 p4est_coarse_cell,
2920 *parallel_forest,
2921 this->my_subdomain);
2922 }
2923 }
2924
2925 // check mesh for ghost cells, refine as necessary. iterate over
2926 // every ghostquadrant, find corresponding deal coarsecell and
2927 // recurse.
2928 typename ::internal::p4est::types<dim>::quadrant *quadr;
2929 types::subdomain_id ghost_owner = 0;
2930 typename ::internal::p4est::types<dim>::topidx ghost_tree = 0;
2931
2932 for (unsigned int g_idx = 0;
2933 g_idx < parallel_ghost->ghosts.elem_count;
2934 ++g_idx)
2935 {
2936 while (g_idx >= static_cast<unsigned int>(
2937 parallel_ghost->proc_offsets[ghost_owner + 1]))
2938 ++ghost_owner;
2939 while (g_idx >= static_cast<unsigned int>(
2940 parallel_ghost->tree_offsets[ghost_tree + 1]))
2941 ++ghost_tree;
2942
2943 quadr = static_cast<
2944 typename ::internal::p4est::types<dim>::quadrant *>(
2945 sc_array_index(&parallel_ghost->ghosts, g_idx));
2946
2947 unsigned int coarse_cell_index =
2948 p4est_tree_to_coarse_cell_permutation[ghost_tree];
2949
2950 match_quadrant<dim, spacedim>(this,
2951 coarse_cell_index,
2952 *quadr,
2953 ghost_owner);
2954 }
2955
2956 // Fix all the flags to make sure we have a consistent local
2957 // mesh. For some reason periodic boundaries involving artificial
2958 // cells are not obeying the 2:1 ratio that we require (and that is
2959 // enforced by p4est between active cells). So, here we will loop
2960 // refining across periodic boundaries until 2:1 is satisfied. Note
2961 // that we are using the base class (sequential) prepare and execute
2962 // calls here, not involving communication, because we are only
2963 // trying to recreate a local triangulation from the p4est data.
2964 {
2965 bool mesh_changed = true;
2966 unsigned int loop_counter = 0;
2967
2968 do
2969 {
2972
2973 this->update_periodic_face_map();
2974
2975 mesh_changed =
2976 enforce_mesh_balance_over_periodic_boundaries(*this);
2977
2978 // We can't be sure that we won't run into a situation where we
2979 // can not reconcile mesh smoothing and balancing of periodic
2980 // faces. As we don't know what else to do, at least abort with
2981 // an error message.
2982 ++loop_counter;
2983
2985 loop_counter < 32,
2986 ExcMessage(
2987 "Infinite loop in "
2988 "parallel::distributed::Triangulation::copy_local_forest_to_triangulation() "
2989 "for periodic boundaries detected. Aborting."));
2990 }
2991 while (mesh_changed);
2992 }
2993
2994 // see if any flags are still set
2995 mesh_changed =
2996 std::any_of(this->begin_active(),
2997 active_cell_iterator{this->end()},
2998 [](const CellAccessor<dim, spacedim> &cell) {
2999 return cell.refine_flag_set() ||
3000 cell.coarsen_flag_set();
3001 });
3002
3003 // actually do the refinement to change the local mesh by
3004 // calling the base class refinement function directly
3005 try
3006 {
3009 }
3010 catch (
3012 {
3013 // the underlying triangulation should not be checking for
3014 // distorted cells
3016 }
3017 }
3018 while (mesh_changed);
3019
3020 if constexpr (running_in_debug_mode())
3021 {
3022 // check if correct number of ghosts is created
3023 unsigned int num_ghosts = 0;
3024
3025 for (const auto &cell : this->active_cell_iterators())
3026 {
3027 if (cell->subdomain_id() != this->my_subdomain &&
3028 cell->subdomain_id() != numbers::artificial_subdomain_id)
3029 ++num_ghosts;
3030 }
3031
3032 Assert(num_ghosts == parallel_ghost->ghosts.elem_count,
3034 }
3035
3036
3037
3038 // fill level_subdomain_ids for geometric multigrid
3039 // the level ownership of a cell is defined as the owner if the cell is
3040 // active or as the owner of child(0) we need this information for all
3041 // our ancestors and the same-level neighbors of our own cells (=level
3042 // ghosts)
3043 if (settings & construct_multigrid_hierarchy)
3044 {
3045 // step 1: We set our own ids all the way down and all the others to
3046 // -1. Note that we do not fill other cells we could figure out the
3047 // same way, because we might accidentally set an id for a cell that
3048 // is not a ghost cell.
3049 for (unsigned int lvl = this->n_levels(); lvl > 0;)
3050 {
3051 --lvl;
3052 for (const auto &cell : this->cell_iterators_on_level(lvl))
3053 {
3054 if ((cell->is_active() &&
3055 cell->subdomain_id() ==
3056 this->locally_owned_subdomain()) ||
3057 (cell->has_children() &&
3058 cell->child(0)->level_subdomain_id() ==
3059 this->locally_owned_subdomain()))
3060 cell->set_level_subdomain_id(
3061 this->locally_owned_subdomain());
3062 else
3063 {
3064 // not our cell
3065 cell->set_level_subdomain_id(
3067 }
3068 }
3069 }
3070
3071 // step 2: make sure all the neighbors to our level_cells exist.
3072 // Need to look up in p4est...
3073 std::vector<std::vector<bool>> marked_vertices(this->n_levels());
3074 for (unsigned int lvl = 0; lvl < this->n_levels(); ++lvl)
3075 marked_vertices[lvl] = mark_locally_active_vertices_on_level(lvl);
3076
3077 for (const auto &cell : this->cell_iterators_on_level(0))
3078 {
3079 typename ::internal::p4est::types<dim>::quadrant
3080 p4est_coarse_cell;
3081 const unsigned int tree_index =
3082 coarse_cell_to_p4est_tree_permutation[cell->index()];
3083 typename ::internal::p4est::types<dim>::tree *tree =
3084 init_tree(cell->index());
3085
3086 ::internal::p4est::init_coarse_quadrant<dim>(
3087 p4est_coarse_cell);
3088
3089 determine_level_subdomain_id_recursively<dim, spacedim>(
3090 *tree,
3091 tree_index,
3092 cell,
3093 p4est_coarse_cell,
3094 *parallel_forest,
3095 this->my_subdomain,
3096 marked_vertices);
3097 }
3098
3099 // step 3: make sure we have the parent of our level cells
3100 for (unsigned int lvl = this->n_levels(); lvl > 0;)
3101 {
3102 --lvl;
3103 for (const auto &cell : this->cell_iterators_on_level(lvl))
3104 {
3105 if (cell->has_children())
3106 for (unsigned int c = 0;
3107 c < GeometryInfo<dim>::max_children_per_cell;
3108 ++c)
3109 {
3110 if (cell->child(c)->level_subdomain_id() ==
3111 this->locally_owned_subdomain())
3112 {
3113 // at least one of the children belongs to us, so
3114 // make sure we set the level subdomain id
3115 const types::subdomain_id mark =
3116 cell->child(0)->level_subdomain_id();
3118 ExcInternalError()); // we should know the
3119 // child(0)
3120 cell->set_level_subdomain_id(mark);
3121 break;
3122 }
3123 }
3124 }
3125 }
3126 }
3127
3128
3129
3130 if constexpr (running_in_debug_mode())
3131 {
3132 // check that our local copy has exactly as many cells as the p4est
3133 // original (at least if we are on only one processor); for parallel
3134 // computations, we want to check that we have at least as many as
3135 // p4est stores locally (in the future we should check that we have
3136 // exactly as many non-artificial cells as
3137 // parallel_forest->local_num_quadrants)
3138 {
3139 const unsigned int total_local_cells = this->n_active_cells();
3140
3141
3142 if (Utilities::MPI::n_mpi_processes(this->mpi_communicator) == 1)
3143 {
3144 Assert(static_cast<unsigned int>(
3145 parallel_forest->local_num_quadrants) ==
3146 total_local_cells,
3148 }
3149 else
3150 {
3151 Assert(static_cast<unsigned int>(
3152 parallel_forest->local_num_quadrants) <=
3153 total_local_cells,
3155 }
3156
3157 // count the number of owned, active cells and compare with p4est.
3158 unsigned int n_owned = 0;
3159 for (const auto &cell : this->active_cell_iterators())
3160 {
3161 if (cell->subdomain_id() == this->my_subdomain)
3162 ++n_owned;
3163 }
3164
3165 Assert(static_cast<unsigned int>(
3166 parallel_forest->local_num_quadrants) == n_owned,
3168 }
3169 }
3170
3171 this->smooth_grid = save_smooth;
3172
3173 // finally, after syncing the parallel_forest with the triangulation,
3174 // also update the cell_relations, which will be used for
3175 // repartitioning, further refinement/coarsening, and unpacking
3176 // of stored or transferred data.
3177 update_cell_relations();
3178 }
3179
3180
3181
3182 template <int dim, int spacedim>
3186 {
3187 // Call the other function
3188 std::vector<Point<dim>> point{p};
3189 std::vector<types::subdomain_id> owner = find_point_owner_rank(point);
3190
3191 return owner[0];
3192 }
3193
3194
3195
3196 template <int dim, int spacedim>
3198 std::vector<types::subdomain_id> Triangulation<dim, spacedim>::
3199 find_point_owner_rank(const std::vector<Point<dim>> &points)
3200 {
3201 // We can only use this function if vertices are communicated to p4est
3202 AssertThrow(this->are_vertices_communicated_to_p4est(),
3203 ExcMessage(
3204 "Vertices need to be communicated to p4est to use this "
3205 "function. This must explicitly be turned on in the "
3206 "settings of the triangulation's constructor."));
3207
3208 // We can only use this function if all manifolds are flat
3209 for (const auto &manifold_id : this->get_manifold_ids())
3210 {
3212 manifold_id == numbers::flat_manifold_id,
3213 ExcMessage(
3214 "This function can only be used if the triangulation "
3215 "has no other manifold than a Cartesian (flat) manifold attached."));
3216 }
3217
3218 // Create object for callback
3219 PartitionSearch<dim> partition_search;
3220
3221 // Pointer should be this triangulation before we set it to something else
3222 Assert(parallel_forest->user_pointer == this, ExcInternalError());
3223
3224 // re-assign p4est's user pointer
3225 parallel_forest->user_pointer = &partition_search;
3226
3227 //
3228 // Copy points into p4est internal array data struct
3229 //
3230 // pointer to an array of points.
3231 sc_array_t *point_sc_array;
3232 // allocate memory for a number of dim-dimensional points including their
3233 // MPI rank, i.e., dim + 1 fields
3234 point_sc_array =
3235 sc_array_new_count(sizeof(double[dim + 1]), points.size());
3236
3237 // now assign the actual value
3238 for (size_t i = 0; i < points.size(); ++i)
3239 {
3240 // alias
3241 const Point<dim> &p = points[i];
3242 // get a non-const view of the array
3243 double *this_sc_point =
3244 static_cast<double *>(sc_array_index_ssize_t(point_sc_array, i));
3245 // fill this with the point data
3246 for (unsigned int d = 0; d < dim; ++d)
3247 {
3248 this_sc_point[d] = p(d);
3249 }
3250 this_sc_point[dim] = -1.0; // owner rank
3251 }
3252
3254 parallel_forest,
3255 /* execute quadrant function when leaving quadrant */
3256 static_cast<int>(false),
3257 &PartitionSearch<dim>::local_quadrant_fn,
3258 &PartitionSearch<dim>::local_point_fn,
3259 point_sc_array);
3260
3261 // copy the points found to an std::array
3262 std::vector<types::subdomain_id> owner_rank(
3263 points.size(), numbers::invalid_subdomain_id);
3264
3265 // fill the array
3266 for (size_t i = 0; i < points.size(); ++i)
3267 {
3268 // get a non-const view of the array
3269 double *this_sc_point =
3270 static_cast<double *>(sc_array_index_ssize_t(point_sc_array, i));
3271 Assert(this_sc_point[dim] >= 0. || this_sc_point[dim] == -1.,
3273 if (this_sc_point[dim] < 0.)
3274 owner_rank[i] = numbers::invalid_subdomain_id;
3275 else
3276 owner_rank[i] =
3277 static_cast<types::subdomain_id>(this_sc_point[dim]);
3278 }
3279
3280 // reset the internal pointer to this triangulation
3281 parallel_forest->user_pointer = this;
3282
3283 // release the memory (otherwise p4est will complain)
3284 sc_array_destroy_null(&point_sc_array);
3285
3286 return owner_rank;
3287 }
3288
3289
3290
3291 template <int dim, int spacedim>
3293 void Triangulation<dim, spacedim>::execute_coarsening_and_refinement()
3294 {
3295 // do not allow anisotropic refinement
3296 if constexpr (running_in_debug_mode())
3297 {
3298 for (const auto &cell : this->active_cell_iterators())
3299 if (cell->is_locally_owned() && cell->refine_flag_set())
3300 Assert(cell->refine_flag_set() ==
3302 ExcMessage(
3303 "This class does not support anisotropic refinement"));
3304 }
3305
3306
3307 // safety check: p4est has an upper limit on the level of a cell
3308 if (this->n_levels() ==
3310 {
3312 cell = this->begin_active(
3314 cell !=
3316 1);
3317 ++cell)
3318 {
3320 !(cell->refine_flag_set()),
3321 ExcMessage(
3322 "Fatal Error: maximum refinement level of p4est reached."));
3323 }
3324 }
3325
3326 this->prepare_coarsening_and_refinement();
3327
3328 // signal that refinement is going to happen
3329 this->signals.pre_distributed_refinement();
3330
3331 // now do the work we're supposed to do when we are in charge
3332 // make sure all flags are cleared on cells we don't own, since nothing
3333 // good can come of that if they are still around
3334 for (const auto &cell : this->active_cell_iterators())
3335 if (cell->is_ghost() || cell->is_artificial())
3336 {
3337 cell->clear_refine_flag();
3338 cell->clear_coarsen_flag();
3339 }
3340
3341
3342 // count how many cells will be refined and coarsened, and allocate that
3343 // much memory
3344 RefineAndCoarsenList<dim, spacedim> refine_and_coarsen_list(
3345 *this, p4est_tree_to_coarse_cell_permutation, this->my_subdomain);
3346
3347 // copy refine and coarsen flags into p4est and execute the refinement
3348 // and coarsening. this uses the refine_and_coarsen_list just built,
3349 // which is communicated to the callback functions through
3350 // p4est's user_pointer object
3351 Assert(parallel_forest->user_pointer == this, ExcInternalError());
3352 parallel_forest->user_pointer = &refine_and_coarsen_list;
3353
3354 if (parallel_ghost != nullptr)
3355 {
3357 parallel_ghost);
3358 parallel_ghost = nullptr;
3359 }
3361 parallel_forest,
3362 /* refine_recursive */ false,
3363 &RefineAndCoarsenList<dim, spacedim>::refine_callback,
3364 /*init_callback=*/nullptr);
3366 parallel_forest,
3367 /* coarsen_recursive */ false,
3368 &RefineAndCoarsenList<dim, spacedim>::coarsen_callback,
3369 /*init_callback=*/nullptr);
3370
3371 // make sure all cells in the lists have been consumed
3372 Assert(refine_and_coarsen_list.pointers_are_at_end(), ExcInternalError());
3373
3374 // reset the pointer
3375 parallel_forest->user_pointer = this;
3376
3377 // enforce 2:1 hanging node condition
3379 parallel_forest,
3380 /* face and corner balance */
3381 (dim == 2 ? typename ::internal::p4est::types<dim>::balance_type(
3382 P4EST_CONNECT_FULL) :
3383 typename ::internal::p4est::types<dim>::balance_type(
3384 P8EST_CONNECT_FULL)),
3385 /*init_callback=*/nullptr);
3386
3387 // since refinement and/or coarsening on the parallel forest
3388 // has happened, we need to update the quadrant cell relations
3389 update_cell_relations();
3390
3391 // signals that parallel_forest has been refined and cell relations have
3392 // been updated
3393 this->signals.post_p4est_refinement();
3394
3395 // before repartitioning the mesh, save a copy of the current positions
3396 // of quadrants only if data needs to be transferred later
3397 std::vector<typename ::internal::p4est::types<dim>::gloidx>
3398 previous_global_first_quadrant;
3399
3400 if (this->cell_attached_data.n_attached_data_sets > 0)
3401 {
3402 previous_global_first_quadrant.resize(parallel_forest->mpisize + 1);
3403 std::memcpy(previous_global_first_quadrant.data(),
3404 parallel_forest->global_first_quadrant,
3405 sizeof(
3406 typename ::internal::p4est::types<dim>::gloidx) *
3407 (parallel_forest->mpisize + 1));
3408 }
3409
3410 if (!(settings & no_automatic_repartitioning))
3411 {
3412 // partition the new mesh between all processors. If cell weights
3413 // have not been given balance the number of cells.
3414 if (this->signals.weight.empty())
3416 parallel_forest,
3417 /* prepare coarsening */ 1,
3418 /* weight_callback */ nullptr);
3419 else
3420 {
3421 // get cell weights for a weighted repartitioning.
3422 const std::vector<unsigned int> cell_weights = get_cell_weights();
3423
3424 // verify that the global sum of weights is larger than 0
3425 Assert(Utilities::MPI::sum(std::accumulate(cell_weights.begin(),
3426 cell_weights.end(),
3427 std::uint64_t(0)),
3428 this->mpi_communicator) > 0,
3429 ExcMessage(
3430 "The global sum of weights over all active cells "
3431 "is zero. Please verify how you generate weights."));
3432
3433 PartitionWeights<dim, spacedim> partition_weights(cell_weights);
3434
3435 // attach (temporarily) a pointer to the cell weights through
3436 // p4est's user_pointer object
3437 Assert(parallel_forest->user_pointer == this, ExcInternalError());
3438 parallel_forest->user_pointer = &partition_weights;
3439
3441 parallel_forest,
3442 /* prepare coarsening */ 1,
3443 /* weight_callback */
3444 &PartitionWeights<dim, spacedim>::cell_weight);
3445
3446 // release data
3448 parallel_forest, 0, nullptr, nullptr);
3449 // reset the user pointer to its previous state
3450 parallel_forest->user_pointer = this;
3451 }
3452 }
3453
3454 // pack data before triangulation gets updated
3455 if (this->cell_attached_data.n_attached_data_sets > 0)
3456 {
3457 this->data_serializer.pack_data(
3458 this->local_cell_relations,
3459 this->cell_attached_data.pack_callbacks_fixed,
3460 this->cell_attached_data.pack_callbacks_variable,
3461 this->get_mpi_communicator());
3462 }
3463
3464 // finally copy back from local part of tree to deal.II
3465 // triangulation. before doing so, make sure there are no refine or
3466 // coarsen flags pending
3467 for (const auto &cell : this->active_cell_iterators())
3468 {
3469 cell->clear_refine_flag();
3470 cell->clear_coarsen_flag();
3471 }
3472
3473 try
3474 {
3475 copy_local_forest_to_triangulation();
3476 }
3477 catch (const typename Triangulation<dim>::DistortedCellList &)
3478 {
3479 // the underlying triangulation should not be checking for distorted
3480 // cells
3482 }
3483
3484 // transfer data after triangulation got updated
3485 if (this->cell_attached_data.n_attached_data_sets > 0)
3486 {
3487 this->execute_transfer(parallel_forest,
3488 previous_global_first_quadrant.data());
3489
3490 // also update the CellStatus information on the new mesh
3491 this->data_serializer.unpack_cell_status(this->local_cell_relations);
3492 }
3493
3494 if constexpr (running_in_debug_mode())
3495 {
3496 // Check that we know the level subdomain ids of all our neighbors.
3497 // This also involves coarser cells that share a vertex if they are
3498 // active.
3499 //
3500 // Example (M= my, O=other):
3501 // *------*
3502 // | |
3503 // | O |
3504 // | |
3505 // *---*---*------*
3506 // | M | M |
3507 // *---*---*
3508 // | | M |
3509 // *---*---*
3510 // ^- the parent can be owned by somebody else, so O is not a
3511 // neighbor
3512 // one level coarser
3513 if (settings & construct_multigrid_hierarchy)
3514 {
3515 for (unsigned int lvl = 0; lvl < this->n_global_levels(); ++lvl)
3516 {
3517 std::vector<bool> active_verts =
3518 this->mark_locally_active_vertices_on_level(lvl);
3519
3520 const unsigned int maybe_coarser_lvl =
3521 (lvl > 0) ? (lvl - 1) : lvl;
3523 cell = this->begin(maybe_coarser_lvl),
3524 endc = this->end(lvl);
3525 for (; cell != endc; ++cell)
3526 if (cell->level() == static_cast<int>(lvl) ||
3527 cell->is_active())
3528 {
3529 const bool is_level_artificial =
3530 (cell->level_subdomain_id() ==
3532 bool need_to_know = false;
3533 for (const unsigned int vertex :
3535 if (active_verts[cell->vertex_index(vertex)])
3536 {
3537 need_to_know = true;
3538 break;
3539 }
3540
3541 Assert(
3542 !need_to_know || !is_level_artificial,
3543 ExcMessage(
3544 "Internal error: the owner of cell" +
3545 cell->id().to_string() +
3546 " is unknown even though it is needed for geometric multigrid."));
3547 }
3548 }
3549 }
3550 }
3551
3552 this->update_periodic_face_map();
3553 this->update_number_cache();
3554
3555 if (this->smooth_grid & ::Triangulation<dim, spacedim>::
3556 match_refinement_across_periodic_boundaries)
3557 {
3558 unsigned int n_mismatched_periodic_faces = 0;
3559 for (const auto &cell : this->active_cell_iterators())
3560 if (cell->is_locally_owned())
3561 for (const unsigned int face : cell->face_indices())
3562 if (cell->has_periodic_neighbor(face) &&
3563 cell->level() != cell->periodic_neighbor(face)->level())
3564 ++n_mismatched_periodic_faces;
3565
3567 Utilities::MPI::sum(n_mismatched_periodic_faces,
3568 this->get_mpi_communicator()) == 0,
3569 ExcMessage(
3570 "p4est produced periodic neighbors at different levels despite the"
3571 "match_refinement_across_periodic_boundaries smoothing flag."));
3572 }
3573
3574 // signal that refinement is finished
3575 this->signals.post_distributed_refinement();
3576 }
3577
3578
3579
3580 template <int dim, int spacedim>
3582 void Triangulation<dim, spacedim>::repartition()
3583 {
3584 if constexpr (running_in_debug_mode())
3585 {
3586 for (const auto &cell : this->active_cell_iterators())
3587 if (cell->is_locally_owned())
3588 Assert(
3589 !cell->refine_flag_set() && !cell->coarsen_flag_set(),
3590 ExcMessage(
3591 "Error: There shouldn't be any cells flagged for coarsening/refinement when calling repartition()."));
3592 }
3593
3594 // signal that repartitioning is going to happen
3595 this->signals.pre_distributed_repartition();
3596
3597 // before repartitioning the mesh, save a copy of the current positions
3598 // of quadrants only if data needs to be transferred later
3599 std::vector<typename ::internal::p4est::types<dim>::gloidx>
3600 previous_global_first_quadrant;
3601
3602 if (this->cell_attached_data.n_attached_data_sets > 0)
3603 {
3604 previous_global_first_quadrant.resize(parallel_forest->mpisize + 1);
3605 std::memcpy(previous_global_first_quadrant.data(),
3606 parallel_forest->global_first_quadrant,
3607 sizeof(
3608 typename ::internal::p4est::types<dim>::gloidx) *
3609 (parallel_forest->mpisize + 1));
3610 }
3611
3612 if (this->signals.weight.empty())
3613 {
3614 // no cell weights given -- call p4est's 'partition' without a
3615 // callback for cell weights
3617 parallel_forest,
3618 /* prepare coarsening */ 1,
3619 /* weight_callback */ nullptr);
3620 }
3621 else
3622 {
3623 // get cell weights for a weighted repartitioning.
3624 const std::vector<unsigned int> cell_weights = get_cell_weights();
3625
3626 // verify that the global sum of weights is larger than 0
3627 Assert(Utilities::MPI::sum(std::accumulate(cell_weights.begin(),
3628 cell_weights.end(),
3629 std::uint64_t(0)),
3630 this->mpi_communicator) > 0,
3631 ExcMessage(
3632 "The global sum of weights over all active cells "
3633 "is zero. Please verify how you generate weights."));
3634
3635 PartitionWeights<dim, spacedim> partition_weights(cell_weights);
3636
3637 // attach (temporarily) a pointer to the cell weights through
3638 // p4est's user_pointer object
3639 Assert(parallel_forest->user_pointer == this, ExcInternalError());
3640 parallel_forest->user_pointer = &partition_weights;
3641
3643 parallel_forest,
3644 /* prepare coarsening */ 1,
3645 /* weight_callback */
3646 &PartitionWeights<dim, spacedim>::cell_weight);
3647
3648 // reset the user pointer to its previous state
3649 parallel_forest->user_pointer = this;
3650 }
3651
3652 // pack data before triangulation gets updated
3653 if (this->cell_attached_data.n_attached_data_sets > 0)
3654 {
3655 this->data_serializer.pack_data(
3656 this->local_cell_relations,
3657 this->cell_attached_data.pack_callbacks_fixed,
3658 this->cell_attached_data.pack_callbacks_variable,
3659 this->get_mpi_communicator());
3660 }
3661
3662 try
3663 {
3664 copy_local_forest_to_triangulation();
3665 }
3666 catch (const typename Triangulation<dim>::DistortedCellList &)
3667 {
3668 // the underlying triangulation should not be checking for distorted
3669 // cells
3671 }
3672
3673 // transfer data after triangulation got updated
3674 if (this->cell_attached_data.n_attached_data_sets > 0)
3675 {
3676 this->execute_transfer(parallel_forest,
3677 previous_global_first_quadrant.data());
3678 }
3679
3680 this->update_periodic_face_map();
3681
3682 // update how many cells, edges, etc, we store locally
3683 this->update_number_cache();
3684
3685 // signal that repartitioning is finished
3686 this->signals.post_distributed_repartition();
3687 }
3688
3689
3690
3691 template <int dim, int spacedim>
3693 const std::vector<types::global_dof_index>
3695 const
3696 {
3697 return p4est_tree_to_coarse_cell_permutation;
3698 }
3699
3700
3701
3702 template <int dim, int spacedim>
3704 const std::vector<types::global_dof_index>
3706 const
3707 {
3708 return coarse_cell_to_p4est_tree_permutation;
3709 }
3710
3711
3712
3713 template <int dim, int spacedim>
3715 std::vector<bool> Triangulation<dim, spacedim>::
3716 mark_locally_active_vertices_on_level(const int level) const
3717 {
3718 Assert(dim > 1, ExcNotImplemented());
3719
3720 std::vector<bool> marked_vertices(this->n_vertices(), false);
3721 for (const auto &cell : this->cell_iterators_on_level(level))
3722 if (cell->level_subdomain_id() == this->locally_owned_subdomain())
3723 for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
3724 marked_vertices[cell->vertex_index(v)] = true;
3725
3731 // When a connectivity in the code below is detected, the assignment
3732 // 'marked_vertices[v1] = marked_vertices[v2] = true' makes sure that
3733 // the information about the periodicity propagates back to vertices on
3734 // cells that are not owned locally. However, in the worst case we want
3735 // to connect to a vertex that is 'dim' hops away from the locally owned
3736 // cell. Depending on the order of the periodic face map, we might
3737 // connect to that point by chance or miss it. However, after looping
3738 // through all the periodic directions (which are at most as many as
3739 // the number of space dimensions) we can be sure that all connections
3740 // to vertices have been created.
3741 for (unsigned int repetition = 0; repetition < dim; ++repetition)
3742 for (const auto &it : this->get_periodic_face_map())
3743 {
3744 const cell_iterator &cell_1 = it.first.first;
3745 const unsigned int face_no_1 = it.first.second;
3746 const cell_iterator &cell_2 = it.second.first.first;
3747 const unsigned int face_no_2 = it.second.first.second;
3748 const auto combined_orientation = it.second.second;
3749 const auto [orientation, rotation, flip] =
3750 ::internal::split_face_orientation(combined_orientation);
3751
3752 if (cell_1->level() == level && cell_2->level() == level)
3753 {
3754 for (unsigned int v = 0;
3755 v < GeometryInfo<dim - 1>::vertices_per_cell;
3756 ++v)
3757 {
3758 // take possible non-standard orientation of faces into
3759 // account
3760 const unsigned int vface0 =
3762 v, orientation, flip, rotation);
3763 if (marked_vertices[cell_1->face(face_no_1)->vertex_index(
3764 vface0)] ||
3765 marked_vertices[cell_2->face(face_no_2)->vertex_index(
3766 v)])
3767 marked_vertices[cell_1->face(face_no_1)->vertex_index(
3768 vface0)] =
3769 marked_vertices[cell_2->face(face_no_2)->vertex_index(
3770 v)] = true;
3771 }
3772 }
3773 }
3774
3775 return marked_vertices;
3776 }
3777
3778
3779
3780 template <int dim, int spacedim>
3782 unsigned int Triangulation<dim, spacedim>::
3783 coarse_cell_id_to_coarse_cell_index(
3784 const types::coarse_cell_id coarse_cell_id) const
3785 {
3786 return p4est_tree_to_coarse_cell_permutation[coarse_cell_id];
3787 }
3788
3789
3790
3791 template <int dim, int spacedim>
3795 const unsigned int coarse_cell_index) const
3796 {
3797 return coarse_cell_to_p4est_tree_permutation[coarse_cell_index];
3798 }
3799
3800
3801
3802 template <int dim, int spacedim>
3804 void Triangulation<dim, spacedim>::add_periodicity(
3805 const std::vector<::GridTools::PeriodicFacePair<cell_iterator>>
3806 &periodicity_vector)
3807 {
3808 Assert(triangulation_has_content == true,
3809 ExcMessage("The triangulation is empty!"));
3810 Assert(this->n_levels() == 1,
3811 ExcMessage("The triangulation is refined!"));
3812
3813 // call the base class for storing the periodicity information; we must
3814 // do this before going to p4est and rebuilding the triangulation to get
3815 // the level subdomain ids correct in the multigrid case
3817
3818 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
3819 const auto face_reference_cell = ReferenceCells::get_hypercube<dim - 1>();
3820 for (const auto &face_pair : periodicity_vector)
3821 {
3822 const cell_iterator first_cell = face_pair.cell[0];
3823 const cell_iterator second_cell = face_pair.cell[1];
3824 const unsigned int face_left = face_pair.face_idx[0];
3825 const unsigned int face_right = face_pair.face_idx[1];
3826
3827 // respective cells of the matching faces in p4est
3828 const unsigned int tree_left =
3829 coarse_cell_to_p4est_tree_permutation[first_cell->index()];
3830 const unsigned int tree_right =
3831 coarse_cell_to_p4est_tree_permutation[second_cell->index()];
3832
3833 // p4est wants to know which corner the first corner on the face with
3834 // the lower id is mapped to on the face with with the higher id. For
3835 // d==2 there are only two possibilities: i.e., face_pair.orientation
3836 // must be 0 or 1. For d==3 we have to use a lookup table. The result
3837 // is given below.
3838
3839 unsigned int p4est_orientation = 0;
3840 if (dim == 2)
3841 {
3842 AssertIndexRange(face_pair.orientation, 2);
3843 p4est_orientation = face_pair.orientation ==
3845 0u :
3846 1u;
3847 }
3848 else
3849 {
3850 const unsigned int face_idx_list[] = {face_left, face_right};
3851 const cell_iterator cell_list[] = {first_cell, second_cell};
3852 unsigned int lower_idx, higher_idx;
3853 types::geometric_orientation orientation;
3854 if (face_left <= face_right)
3855 {
3856 higher_idx = 1;
3857 lower_idx = 0;
3858 orientation =
3859 face_reference_cell.get_inverse_combined_orientation(
3860 face_pair.orientation);
3861 }
3862 else
3863 {
3864 higher_idx = 0;
3865 lower_idx = 1;
3866 orientation = face_pair.orientation;
3867 }
3868
3869 // get the cell index of the first index on the face with the
3870 // lower id
3871 unsigned int first_p4est_idx_on_cell =
3872 p8est_face_corners[face_idx_list[lower_idx]][0];
3873 unsigned int first_dealii_idx_on_face =
3875 for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_face;
3876 ++i)
3877 {
3878 const unsigned int first_dealii_idx_on_cell =
3880 face_idx_list[lower_idx],
3881 i,
3882 cell_list[lower_idx]->face_orientation(
3883 face_idx_list[lower_idx]),
3884 cell_list[lower_idx]->face_flip(face_idx_list[lower_idx]),
3885 cell_list[lower_idx]->face_rotation(
3886 face_idx_list[lower_idx]));
3887 if (first_p4est_idx_on_cell == first_dealii_idx_on_cell)
3888 {
3889 first_dealii_idx_on_face = i;
3890 break;
3891 }
3892 }
3893 Assert(first_dealii_idx_on_face != numbers::invalid_unsigned_int,
3895
3896 // Now map dealii_idx_on_face according to the orientation.
3897 const unsigned int second_dealii_idx_on_face =
3898 reference_cell.standard_to_real_face_vertex(
3899 first_dealii_idx_on_face,
3900 face_idx_list[lower_idx],
3901 orientation);
3902 const unsigned int second_dealii_idx_on_cell =
3903 reference_cell.face_to_cell_vertices(
3904 face_idx_list[higher_idx],
3905 second_dealii_idx_on_face,
3906 cell_list[higher_idx]->combined_face_orientation(
3907 face_idx_list[higher_idx]));
3908 // map back to p4est
3909 const unsigned int second_p4est_idx_on_face =
3910 p8est_corner_face_corners[second_dealii_idx_on_cell]
3911 [face_idx_list[higher_idx]];
3912 p4est_orientation = second_p4est_idx_on_face;
3913 }
3914
3916 connectivity,
3917 tree_left,
3918 tree_right,
3919 face_left,
3920 face_right,
3921 p4est_orientation);
3922 }
3923
3924
3926 connectivity) == 1,
3928
3929 // now create a forest out of the connectivity data structure
3932 this->mpi_communicator,
3933 connectivity,
3934 /* minimum initial number of quadrants per tree */ 0,
3935 /* minimum level of upfront refinement */ 0,
3936 /* use uniform upfront refinement */ 1,
3937 /* user_data_size = */ 0,
3938 /* user_data_constructor = */ nullptr,
3939 /* user_pointer */ this);
3940
3941 try
3942 {
3943 copy_local_forest_to_triangulation();
3944 }
3945 catch (const typename Triangulation<dim>::DistortedCellList &)
3946 {
3947 // the underlying triangulation should not be checking for distorted
3948 // cells
3950 }
3951
3952 // The range of ghost_owners might have changed so update that
3953 // information
3954 this->update_number_cache();
3955 }
3956
3957
3958
3959 template <int dim, int spacedim>
3961 std::size_t Triangulation<dim, spacedim>::memory_consumption() const
3962 {
3963 std::size_t mem =
3966 MemoryConsumption::memory_consumption(triangulation_has_content) +
3968 MemoryConsumption::memory_consumption(parallel_forest) +
3970 this->cell_attached_data.n_attached_data_sets) +
3971 // MemoryConsumption::memory_consumption(cell_attached_data.pack_callbacks_fixed)
3972 // +
3973 // MemoryConsumption::memory_consumption(cell_attached_data.pack_callbacks_variable)
3974 // +
3975 // TODO[TH]: how?
3977 coarse_cell_to_p4est_tree_permutation) +
3979 p4est_tree_to_coarse_cell_permutation) +
3980 memory_consumption_p4est();
3981
3982 return mem;
3983 }
3984
3985
3986
3987 template <int dim, int spacedim>
3989 std::size_t Triangulation<dim, spacedim>::memory_consumption_p4est() const
3990 {
3991 return ::internal::p4est::functions<dim>::forest_memory_used(
3992 parallel_forest) +
3994 connectivity);
3995 }
3996
3997
3998
3999 template <int dim, int spacedim>
4001 void Triangulation<dim, spacedim>::copy_triangulation(
4002 const ::Triangulation<dim, spacedim> &other_tria)
4003 {
4004 if (const ::parallel::distributed::Triangulation<dim, spacedim>
4005 *other_distributed =
4006 dynamic_cast<const ::parallel::distributed::
4007 Triangulation<dim, spacedim> *>(&other_tria))
4008 copy_triangulation(other_tria, other_distributed->settings);
4009 else
4010 copy_triangulation(other_tria, default_setting);
4011 }
4012
4013
4014
4015 template <int dim, int spacedim>
4017 void Triangulation<dim, spacedim>::copy_triangulation(
4018 const ::Triangulation<dim, spacedim> &other_tria,
4019 const Settings settings)
4020 {
4021 Assert(
4022 (dynamic_cast<
4023 const ::parallel::distributed::Triangulation<dim, spacedim> *>(
4024 &other_tria)) ||
4025 (other_tria.n_global_levels() == 1),
4027
4029
4030 try
4031 {
4033 copy_triangulation(other_tria);
4034 }
4035 catch (
4036 const typename ::Triangulation<dim, spacedim>::DistortedCellList
4037 &)
4038 {
4039 // the underlying triangulation should not be checking for distorted
4040 // cells
4042 }
4043
4044 if (const ::parallel::distributed::Triangulation<dim, spacedim>
4045 *other_distributed =
4046 dynamic_cast<const ::parallel::distributed::
4047 Triangulation<dim, spacedim> *>(&other_tria))
4048 {
4049 // use settings from the provided parameter instead of copying them
4050 this->settings = settings;
4051 // copy parallel distributed specifics
4052 triangulation_has_content =
4053 other_distributed->triangulation_has_content;
4054 coarse_cell_to_p4est_tree_permutation =
4055 other_distributed->coarse_cell_to_p4est_tree_permutation;
4056 p4est_tree_to_coarse_cell_permutation =
4057 other_distributed->p4est_tree_to_coarse_cell_permutation;
4058
4059 // create deep copy of connectivity graph
4060 typename ::internal::p4est::types<dim>::connectivity
4061 *temp_connectivity = const_cast<
4062 typename ::internal::p4est::types<dim>::connectivity *>(
4063 other_distributed->connectivity);
4064 connectivity =
4065 ::internal::p4est::copy_connectivity<dim>(temp_connectivity);
4066
4067 // create deep copy of parallel forest
4068 typename ::internal::p4est::types<dim>::forest *temp_forest =
4069 const_cast<typename ::internal::p4est::types<dim>::forest *>(
4070 other_distributed->parallel_forest);
4071 parallel_forest =
4073 false);
4074 parallel_forest->connectivity = connectivity;
4075 parallel_forest->user_pointer = this;
4076 }
4077 else
4078 {
4079 triangulation_has_content = true;
4080 setup_coarse_cell_to_p4est_tree_permutation();
4081 copy_new_triangulation_to_p4est(std::integral_constant<int, dim>());
4082 }
4083
4084 try
4085 {
4086 copy_local_forest_to_triangulation();
4087 }
4088 catch (const typename Triangulation<dim>::DistortedCellList &)
4089 {
4090 // the underlying triangulation should not be checking for distorted
4091 // cells
4093 }
4094
4095 this->update_periodic_face_map();
4096 this->update_number_cache();
4097 }
4098
4099
4100
4101 template <int dim, int spacedim>
4103 void Triangulation<dim, spacedim>::update_cell_relations()
4104 {
4105 // reorganize memory for local_cell_relations
4106 this->local_cell_relations.resize(parallel_forest->local_num_quadrants);
4107 this->local_cell_relations.shrink_to_fit();
4108
4109 // recurse over p4est
4110 for (const auto &cell : this->cell_iterators_on_level(0))
4111 {
4112 // skip coarse cells that are not ours
4113 if (tree_exists_locally<dim, spacedim>(
4114 parallel_forest,
4115 coarse_cell_to_p4est_tree_permutation[cell->index()]) == false)
4116 continue;
4117
4118 // initialize auxiliary top level p4est quadrant
4119 typename ::internal::p4est::types<dim>::quadrant
4120 p4est_coarse_cell;
4121 ::internal::p4est::init_coarse_quadrant<dim>(p4est_coarse_cell);
4122
4123 // determine tree to start recursion on
4124 typename ::internal::p4est::types<dim>::tree *tree =
4125 init_tree(cell->index());
4126
4127 update_cell_relations_recursively<dim, spacedim>(
4128 this->local_cell_relations, *tree, cell, p4est_coarse_cell);
4129 }
4130 }
4131
4132
4133
4134 template <int dim, int spacedim>
4136 std::vector<unsigned int> Triangulation<dim, spacedim>::get_cell_weights()
4137 const
4138 {
4139 // check if local_cell_relations have been previously gathered
4140 // correctly
4141 Assert(this->local_cell_relations.size() ==
4142 static_cast<unsigned int>(parallel_forest->local_num_quadrants),
4144
4145 // Allocate the space for the weights. We reserve an integer for each
4146 // locally owned quadrant on the already refined p4est object.
4147 std::vector<unsigned int> weights;
4148 weights.reserve(this->local_cell_relations.size());
4149
4150 // Iterate over p4est and Triangulation relations
4151 // to find refined/coarsened/kept
4152 // cells. Then append weight.
4153 // Note that we need to follow the p4est ordering
4154 // instead of the deal.II ordering to get the weights
4155 // in the same order p4est will encounter them during repartitioning.
4156 for (const auto &[cell_it, cell_status] : this->local_cell_relations)
4157 {
4158 weights.push_back(this->signals.weight(cell_it, cell_status));
4159 }
4160
4161 return weights;
4162 }
4163
4164
4165
4166 template <int spacedim>
4169 const MPI_Comm mpi_communicator,
4170 const typename ::Triangulation<1, spacedim>::MeshSmoothing
4171 smooth_grid,
4172 const Settings /*settings*/)
4173 : ::parallel::DistributedTriangulationBase<1, spacedim>(
4174 mpi_communicator,
4175 smooth_grid,
4176 false)
4177 {
4179 }
4180
4181
4182 template <int spacedim>
4185 {
4187 }
4188
4189
4190
4191 template <int spacedim>
4193 const std::vector<types::global_dof_index>
4195 const
4196 {
4197 return p4est_tree_to_coarse_cell_permutation;
4198 }
4199
4200
4201
4202 template <int spacedim>
4204 std::map<unsigned int,
4205 std::set<::types::subdomain_id>> Triangulation<1, spacedim>::
4207 const unsigned int /*level*/) const
4208 {
4210
4211 return std::map<unsigned int, std::set<::types::subdomain_id>>();
4212 }
4213
4214
4215
4216 template <int spacedim>
4218 std::vector<bool> Triangulation<1, spacedim>::
4219 mark_locally_active_vertices_on_level(const unsigned int) const
4220 {
4222 return std::vector<bool>();
4223 }
4224
4225
4226
4227 template <int spacedim>
4229 unsigned int Triangulation<1, spacedim>::
4230 coarse_cell_id_to_coarse_cell_index(const types::coarse_cell_id) const
4231 {
4233 return 0;
4234 }
4235
4236
4237
4238 template <int spacedim>
4242 const unsigned int) const
4243 {
4245 return 0;
4246 }
4247
4248
4249
4250 template <int spacedim>
4252 void Triangulation<1, spacedim>::load(const std::string &)
4253 {
4255 }
4256
4257
4258
4259 template <int spacedim>
4261 void Triangulation<1, spacedim>::save(const std::string &) const
4262 {
4264 }
4265
4266
4267
4268 template <int spacedim>
4270 bool Triangulation<1, spacedim>::is_multilevel_hierarchy_constructed() const
4271 {
4273 return false;
4274 }
4275
4276
4277
4278 template <int spacedim>
4280 bool Triangulation<1, spacedim>::are_vertices_communicated_to_p4est() const
4281 {
4283 return false;
4284 }
4285
4286
4287
4288 template <int spacedim>
4290 void Triangulation<1, spacedim>::update_cell_relations()
4291 {
4293 }
4294
4295 } // namespace distributed
4296} // namespace parallel
4297
4298
4299#endif // DEAL_II_WITH_P4EST
4300
4301
4302
4303namespace parallel
4304{
4305 namespace distributed
4306 {
4307 template <int dim, int spacedim>
4310 : distributed_tria(
4311 dynamic_cast<
4312 ::parallel::distributed::Triangulation<dim, spacedim> *>(
4313 &tria))
4314 {
4315#ifdef DEAL_II_WITH_P4EST
4316 if (distributed_tria != nullptr)
4317 {
4318 // Save the current set of refinement flags, and adjust the
4319 // refinement flags to be consistent with the p4est oracle.
4320 distributed_tria->save_coarsen_flags(saved_coarsen_flags);
4321 distributed_tria->save_refine_flags(saved_refine_flags);
4322
4323 for (const auto &[cell, status] :
4324 distributed_tria->local_cell_relations)
4325 {
4326 switch (status)
4327 {
4329 // cell remains unchanged
4330 cell->clear_refine_flag();
4331 cell->clear_coarsen_flag();
4332 break;
4333
4335 // cell will be refined
4336 cell->clear_coarsen_flag();
4337 cell->set_refine_flag();
4338 break;
4339
4341 // children of this cell will be coarsened
4342 for (const auto &child : cell->child_iterators())
4343 {
4344 child->clear_refine_flag();
4345 child->set_coarsen_flag();
4346 }
4347 break;
4348
4350 // do nothing as cell does not exist yet
4351 break;
4352
4353 default:
4355 break;
4356 }
4357 }
4358 }
4359#endif
4360 }
4361
4362
4363
4364 template <int dim, int spacedim>
4366 {
4367#ifdef DEAL_II_WITH_P4EST
4368 if (distributed_tria)
4369 {
4370 // Undo the refinement flags modification.
4371 distributed_tria->load_coarsen_flags(saved_coarsen_flags);
4372 distributed_tria->load_refine_flags(saved_refine_flags);
4373 }
4374#else
4375 // pretend that this destructor does something to silence clang-tidy
4376 (void)distributed_tria;
4377#endif
4378 }
4379 } // namespace distributed
4380} // namespace parallel
4381
4382
4383
4384/*-------------- Explicit Instantiations -------------------------------*/
4385#include "distributed/tria.inst"
4386
4387
*  iterator end()
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  iterator begin()
*  *  const_iterator()=default
CellStatus
Definition cell_status.h:29
@ cell_will_be_refined
@ children_will_be_coarsened
Definition point.h:111
virtual void add_periodicity(const std::vector< GridTools::PeriodicFacePair< cell_iterator > > &)
active_cell_iterator last_active() const
virtual void create_triangulation(const std::vector< Point< spacedim > > &vertices, const std::vector< CellData< dim > > &cells, const SubCellData &subcelldata)
const std::vector< Point< spacedim > > & get_vertices() const
unsigned int n_active_lines() const
unsigned int n_levels() const
cell_iterator end() const
virtual types::coarse_cell_id coarse_cell_index_to_coarse_cell_id(const unsigned int coarse_cell_index) const
virtual void execute_coarsening_and_refinement()
unsigned int n_cells() const
virtual bool prepare_coarsening_and_refinement()
const std::vector< bool > & get_used_vertices() const
void save_refine_flags(std::ostream &out) const
unsigned int n_vertices() const
const std::map< std::pair< cell_iterator, unsigned int >, std::pair< std::pair< cell_iterator, unsigned int >, types::geometric_orientation > > & get_periodic_face_map() const
void save_coarsen_flags(std::ostream &out) const
active_cell_iterator begin_active(const unsigned int level=0) const
virtual std::size_t memory_consumption() const override
Definition tria_base.cc:90
virtual void clear() override
Definition tria_base.cc:686
virtual void copy_triangulation(const ::Triangulation< dim, spacedim > &old_tria) override
Definition tria_base.cc:65
const ObserverPointer< ::parallel::distributed::Triangulation< dim, spacedim > > distributed_tria
Definition tria.h:1191
virtual void clear() override
Definition tria.cc:1809
#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:249
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int level
Definition grid_out.cc:4642
unsigned int vertex_indices[2]
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertNothrow(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
typename ::Triangulation< dim, spacedim >::cell_iterator cell_iterator
Definition tria.h:322
typename ::Triangulation< dim, spacedim >::active_cell_iterator active_cell_iterator
Definition tria.h:343
std::size_t size
Definition mpi.cc:733
void get_vertex_connectivity_of_cells(const Triangulation< dim, spacedim > &triangulation, DynamicSparsityPattern &connectivity)
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:190
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
constexpr const ReferenceCell< dim > & get_hypercube()
void reorder_hierarchical(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices)
T sum(const T &t, const MPI_Comm mpi_communicator)
T logical_or(const T &t, const MPI_Comm mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:118
T broadcast(const MPI_Comm comm, const T &object_to_send, const unsigned int root_process=0)
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1670
bool tree_exists_locally(const typename types< dim >::forest *parallel_forest, const typename types< dim >::topidx coarse_grid_cell)
void exchange_refinement_flags(::parallel::distributed::Triangulation< dim, spacedim > &tria)
Definition tria.cc:54
std::tuple< bool, bool, bool > split_face_orientation(const types::geometric_orientation combined_orientation)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::manifold_id flat_manifold_id
Definition types.h:332
constexpr types::subdomain_id artificial_subdomain_id
Definition types.h:406
constexpr types::subdomain_id invalid_subdomain_id
Definition types.h:385
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
STL namespace.
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
Definition types.h:30
std::uint8_t geometric_orientation
Definition types.h:38
static unsigned int standard_to_real_face_vertex(const unsigned int vertex, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
static unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices()
static bool is_inside_unit_cell(const Point< dim > &p)
static Point< dim > unit_cell_vertex(const unsigned int vertex)