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