deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
grid_tools.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2001 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
14#include <deal.II/base/mpi.h>
15#include <deal.II/base/mpi.templates.h>
19
20#ifdef DEAL_II_WITH_ARBORX
23#endif
24
25#ifdef DEAL_II_WITH_CGAL
28#endif
29
34
38
40#include <deal.II/fe/fe_q.h>
44
49#include <deal.II/grid/tria.h>
52
61#include <deal.II/lac/vector.h>
63
66
68
69#include <boost/random/mersenne_twister.hpp>
70#include <boost/random/uniform_real_distribution.hpp>
71
72#include <array>
73#include <cmath>
74#include <iostream>
75#include <limits>
76#include <list>
77#include <numeric>
78#include <set>
79#include <tuple>
80#include <unordered_map>
81
83
84#ifndef DEAL_II_WITH_ARBORX
85
86// If we configured without ArborX, we still need to have a couple of
87// dummy types that we can reference in code below. They do not
88// actually do anything useful.
89template <int dim, typename Number>
90class BoundingBox;
91
92namespace ArborXWrappers
93{
94 class DistributedTree
95 {
96 public:
97 template <int dim, typename Number>
99 const std::vector<BoundingBox<dim, Number>> &);
100
101 template <typename QueryType>
102 std::pair<std::vector<std::pair<int, int>>, std::vector<int>>
103 query(const QueryType &queries);
104 };
105
106 class BoundingBoxIntersectPredicate
107 {};
108} // namespace ArborXWrappers
109#endif
110
111
112namespace GridTools
113{
114 // define some transformations
115 namespace internal
116 {
117 template <int spacedim>
118 class Shift
119 {
120 public:
122 : shift(shift)
123 {}
126 {
127 return p + shift;
128 }
129
130 private:
132 };
133
134
135 // Transformation to rotate around one of the cartesian z-axis in 2d.
137 {
138 public:
139 explicit Rotate2d(const double angle)
141 Physics::Transformations::Rotations::rotation_matrix_2d(angle))
142 {}
144 operator()(const Point<2> &p) const
145 {
146 return static_cast<Point<2>>(rotation_matrix * p);
147 }
148
149 private:
151 };
152
153
154 // Transformation to rotate around one of the cartesian axes.
156 {
157 public:
158 Rotate3d(const Tensor<1, 3, double> &axis, const double angle)
160 Physics::Transformations::Rotations::rotation_matrix_3d(axis,
161 angle))
162 {}
163
165 operator()(const Point<3> &p) const
166 {
167 return static_cast<Point<3>>(rotation_matrix * p);
168 }
169
170 private:
172 };
173
174
175 template <int spacedim>
176 class Scale
177 {
178 public:
179 explicit Scale(const double factor)
180 : factor(factor)
181 {}
184 {
185 return p * factor;
186 }
187
188 private:
189 const double factor;
190 };
191 } // namespace internal
192
193
194 template <int dim, int spacedim>
195 void
196 shift(const Tensor<1, spacedim> &shift_vector,
197 Triangulation<dim, spacedim> &triangulation)
198 {
199 transform(internal::Shift<spacedim>(shift_vector), triangulation);
200 }
201
202
203
204 template <int dim, int spacedim>
205 void
206 rotate(const double /*angle*/,
207 Triangulation<dim, spacedim> & /*triangulation*/)
208 {
209 AssertThrow(false,
211 "GridTools::rotate() is only available for spacedim = 2."));
212 }
213
214
215
216 template <>
217 void
218 rotate(const double angle, Triangulation<1, 2> &triangulation)
219 {
220 transform(internal::Rotate2d(angle), triangulation);
221 }
222
223
224
225 template <>
226 void
227 rotate(const double angle, Triangulation<2, 2> &triangulation)
228 {
229 transform(internal::Rotate2d(angle), triangulation);
230 }
231
232
233 template <int dim>
234 void
236 const double angle,
237 Triangulation<dim, 3> &triangulation)
238 {
239 transform(internal::Rotate3d(axis, angle), triangulation);
240 }
241
242
243 template <int dim, int spacedim>
244 void
245 scale(const double scaling_factor,
246 Triangulation<dim, spacedim> &triangulation)
247 {
248 Assert(scaling_factor > 0, ExcScalingFactorNotPositive(scaling_factor));
249 transform(internal::Scale<spacedim>(scaling_factor), triangulation);
250 }
251
252
253 namespace internal
254 {
260 void
262 const AffineConstraints<double> &constraints,
264 {
265 const unsigned int n_dofs = S.n();
266 const auto op = linear_operator(S);
267 const auto SF = constrained_linear_operator(constraints, op);
269 prec.initialize(S, 1.2);
270
271 SolverControl control(n_dofs, 1.e-10, false, false);
273 SolverCG<Vector<double>> solver(control, mem);
274
275 Vector<double> f(n_dofs);
276
277 const auto constrained_rhs =
278 constrained_right_hand_side(constraints, op, f);
279 solver.solve(SF, u, constrained_rhs, prec);
280
281 constraints.distribute(u);
282 }
283 } // namespace internal
284
285
286 // Implementation for dimensions except 1
287 template <int dim>
288 void
289 laplace_transform(const std::map<unsigned int, Point<dim>> &new_points,
290 Triangulation<dim> &triangulation,
291 const Function<dim> *coefficient,
292 const bool solve_for_absolute_positions)
293 {
294 if (dim == 1)
296
297 // first provide everything that is needed for solving a Laplace
298 // equation.
299 FE_Q<dim> q1(1);
300
301 DoFHandler<dim> dof_handler(triangulation);
302 dof_handler.distribute_dofs(q1);
303
304 DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
305 DoFTools::make_sparsity_pattern(dof_handler, dsp);
306 dsp.compress();
307
308 SparsityPattern sparsity_pattern;
309 sparsity_pattern.copy_from(dsp);
310 sparsity_pattern.compress();
311
312 SparseMatrix<double> S(sparsity_pattern);
313
314 const QGauss<dim> quadrature(4);
315
318 const auto reference_cell = ReferenceCells::get_hypercube<dim>();
320 reference_cell.template get_default_linear_mapping<dim>(),
321 dof_handler,
322 quadrature,
323 S,
324 coefficient);
325
326 // set up the boundary values for the laplace problem
327 std::array<AffineConstraints<double>, dim> constraints;
328 typename std::map<unsigned int, Point<dim>>::const_iterator map_end =
329 new_points.end();
330
331 // Fill these maps using the data given by new_points
332 for (const auto &cell : dof_handler.active_cell_iterators())
333 {
334 // Loop over all vertices of the cell and see if it is listed in the map
335 // given as first argument of the function. We visit vertices multiple
336 // times, so also check that if we have already added a constraint, we
337 // don't do it a second time again.
338 for (const unsigned int vertex_no : cell->vertex_indices())
339 {
340 const unsigned int vertex_index = cell->vertex_index(vertex_no);
341 const Point<dim> &vertex_point = cell->vertex(vertex_no);
342
343 const typename std::map<unsigned int, Point<dim>>::const_iterator
344 map_iter = new_points.find(vertex_index);
345
346 if (map_iter != map_end)
347 for (unsigned int i = 0; i < dim; ++i)
348 if (constraints[i].is_constrained(
349 cell->vertex_dof_index(vertex_no, 0)) == false)
350 {
351 constraints[i].add_constraint(
352 cell->vertex_dof_index(vertex_no, 0),
353 {},
354 (solve_for_absolute_positions ?
355 map_iter->second[i] :
356 map_iter->second[i] - vertex_point[i]));
357 }
358 }
359 }
360
361 for (unsigned int i = 0; i < dim; ++i)
362 constraints[i].close();
363
364 // solve the dim problems with different right hand sides.
365 Vector<double> us[dim];
366 for (unsigned int i = 0; i < dim; ++i)
367 us[i].reinit(dof_handler.n_dofs());
368
369 // solve linear systems in parallel
371 for (unsigned int i = 0; i < dim; ++i)
372 tasks +=
373 Threads::new_task(&internal::laplace_solve, S, constraints[i], us[i]);
374 tasks.join_all();
375
376 // change the coordinates of the points of the triangulation
377 // according to the computed values
378 std::vector<bool> vertex_touched(triangulation.n_vertices(), false);
379 for (const auto &cell : dof_handler.active_cell_iterators())
380 for (const unsigned int vertex_no : cell->vertex_indices())
381 if (vertex_touched[cell->vertex_index(vertex_no)] == false)
382 {
383 Point<dim> &v = cell->vertex(vertex_no);
384
385 const types::global_dof_index dof_index =
386 cell->vertex_dof_index(vertex_no, 0);
387 for (unsigned int i = 0; i < dim; ++i)
388 if (solve_for_absolute_positions)
389 v[i] = us[i](dof_index);
390 else
391 v[i] += us[i](dof_index);
392
393 vertex_touched[cell->vertex_index(vertex_no)] = true;
394 }
395 }
396
401 template <int dim, int spacedim>
402 void
403 distort_random(const double factor,
404 Triangulation<dim, spacedim> &triangulation,
405 const bool keep_boundary,
406 const unsigned int seed)
407 {
408 // if spacedim>dim we need to make sure that we perturb
409 // points but keep them on
410 // the manifold. however, this isn't implemented right now
411 Assert(spacedim == dim, ExcNotImplemented());
412
413
414 // find the smallest length of the
415 // lines adjacent to the
416 // vertex. take the initial value
417 // to be larger than anything that
418 // might be found: the diameter of
419 // the triangulation, here
420 // estimated by adding up the
421 // diameters of the coarse grid
422 // cells.
423 double almost_infinite_length = 0;
425 triangulation.begin(0);
426 cell != triangulation.end(0);
427 ++cell)
428 almost_infinite_length += cell->diameter();
429
430 std::vector<double> minimal_length(triangulation.n_vertices(),
431 almost_infinite_length);
432
433 // also note if a vertex is at the boundary
434 std::vector<bool> at_boundary(keep_boundary ? triangulation.n_vertices() :
435 0,
436 false);
437 // for parallel::shared::Triangulation we need to work on all vertices,
438 // not just the ones related to locally owned cells;
439 const bool is_parallel_shared =
441 &triangulation) != nullptr);
442 for (const auto &cell : triangulation.active_cell_iterators())
443 if (is_parallel_shared || cell->is_locally_owned())
444 {
445 if (dim > 1)
446 {
447 for (unsigned int i = 0; i < cell->n_lines(); ++i)
448 {
450 line = cell->line(i);
451
452 if (keep_boundary && line->at_boundary())
453 {
454 at_boundary[line->vertex_index(0)] = true;
455 at_boundary[line->vertex_index(1)] = true;
456 }
457
458 minimal_length[line->vertex_index(0)] =
459 std::min(line->diameter(),
460 minimal_length[line->vertex_index(0)]);
461 minimal_length[line->vertex_index(1)] =
462 std::min(line->diameter(),
463 minimal_length[line->vertex_index(1)]);
464 }
465 }
466 else // dim==1
467 {
468 if (keep_boundary)
469 for (unsigned int vertex = 0; vertex < 2; ++vertex)
470 if (cell->at_boundary(vertex) == true)
471 at_boundary[cell->vertex_index(vertex)] = true;
472
473 minimal_length[cell->vertex_index(0)] =
474 std::min(cell->diameter(),
475 minimal_length[cell->vertex_index(0)]);
476 minimal_length[cell->vertex_index(1)] =
477 std::min(cell->diameter(),
478 minimal_length[cell->vertex_index(1)]);
479 }
480 }
481
482 // create a random number generator for the interval [-1,1]
483 boost::random::mt19937 rng(seed);
484 boost::random::uniform_real_distribution<> uniform_distribution(-1, 1);
485
486 // If the triangulation is distributed, we need to
487 // exchange the moved vertices across mpi processes
488 if (auto distributed_triangulation =
490 &triangulation))
491 {
492 const std::vector<bool> locally_owned_vertices =
493 get_locally_owned_vertices(triangulation);
494 std::vector<bool> vertex_moved(triangulation.n_vertices(), false);
495
496 // Next move vertices on locally owned cells
497 for (const auto &cell : triangulation.active_cell_iterators())
498 if (cell->is_locally_owned())
499 {
500 for (const unsigned int vertex_no : cell->vertex_indices())
501 {
502 const unsigned global_vertex_no =
503 cell->vertex_index(vertex_no);
504
505 // ignore this vertex if we shall keep the boundary and
506 // this vertex *is* at the boundary, if it is already moved
507 // or if another process moves this vertex
508 if ((keep_boundary && at_boundary[global_vertex_no]) ||
509 vertex_moved[global_vertex_no] ||
510 !locally_owned_vertices[global_vertex_no])
511 continue;
512
513 // first compute a random shift vector
514 Point<spacedim> shift_vector;
515 for (unsigned int d = 0; d < spacedim; ++d)
516 shift_vector[d] = uniform_distribution(rng);
517
518 shift_vector *= factor * minimal_length[global_vertex_no] /
519 std::sqrt(shift_vector.square());
520
521 // finally move the vertex
522 cell->vertex(vertex_no) += shift_vector;
523 vertex_moved[global_vertex_no] = true;
524 }
525 }
526
527 distributed_triangulation->communicate_locally_moved_vertices(
528 locally_owned_vertices);
529 }
530 else
531 // if this is a sequential triangulation, we could in principle
532 // use the algorithm above, but we'll use an algorithm that we used
533 // before the parallel::distributed::Triangulation was introduced
534 // in order to preserve backward compatibility
535 {
536 // loop over all vertices and compute their new locations
537 const unsigned int n_vertices = triangulation.n_vertices();
538 std::vector<Point<spacedim>> new_vertex_locations(n_vertices);
539 const std::vector<Point<spacedim>> &old_vertex_locations =
540 triangulation.get_vertices();
541
542 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
543 {
544 // ignore this vertex if we will keep the boundary and
545 // this vertex *is* at the boundary
546 if (keep_boundary && at_boundary[vertex])
547 new_vertex_locations[vertex] = old_vertex_locations[vertex];
548 else
549 {
550 // compute a random shift vector
551 Point<spacedim> shift_vector;
552 for (unsigned int d = 0; d < spacedim; ++d)
553 shift_vector[d] = uniform_distribution(rng);
554
555 shift_vector *= factor * minimal_length[vertex] /
556 std::sqrt(shift_vector.square());
557
558 // record new vertex location
559 new_vertex_locations[vertex] =
560 old_vertex_locations[vertex] + shift_vector;
561 }
562 }
563
564 // now do the actual move of the vertices
565 for (const auto &cell : triangulation.active_cell_iterators())
566 for (const unsigned int vertex_no : cell->vertex_indices())
567 cell->vertex(vertex_no) =
568 new_vertex_locations[cell->vertex_index(vertex_no)];
569 }
570
571 // Correct hanging nodes if necessary
572 if (dim >= 2)
573 {
574 // We do the same as in GridTools::transform
575 //
576 // exclude hanging nodes at the boundaries of artificial cells:
577 // these may belong to ghost cells for which we know the exact
578 // location of vertices, whereas the artificial cell may or may
579 // not be further refined, and so we cannot know whether
580 // the location of the hanging node is correct or not
582 cell = triangulation.begin_active(),
583 endc = triangulation.end();
584 for (; cell != endc; ++cell)
585 if (!cell->is_artificial())
586 for (const unsigned int face : cell->face_indices())
587 if (cell->face(face)->has_children() &&
588 !cell->face(face)->at_boundary())
589 {
590 // this face has hanging nodes
591 if (dim == 2)
592 cell->face(face)->child(0)->vertex(1) =
593 (cell->face(face)->vertex(0) +
594 cell->face(face)->vertex(1)) /
595 2;
596 else if (dim == 3)
597 {
598 cell->face(face)->child(0)->vertex(1) =
599 .5 * (cell->face(face)->vertex(0) +
600 cell->face(face)->vertex(1));
601 cell->face(face)->child(0)->vertex(2) =
602 .5 * (cell->face(face)->vertex(0) +
603 cell->face(face)->vertex(2));
604 cell->face(face)->child(1)->vertex(3) =
605 .5 * (cell->face(face)->vertex(1) +
606 cell->face(face)->vertex(3));
607 cell->face(face)->child(2)->vertex(3) =
608 .5 * (cell->face(face)->vertex(2) +
609 cell->face(face)->vertex(3));
610
611 // center of the face
612 cell->face(face)->child(0)->vertex(3) =
613 .25 * (cell->face(face)->vertex(0) +
614 cell->face(face)->vertex(1) +
615 cell->face(face)->vertex(2) +
616 cell->face(face)->vertex(3));
617 }
618 }
619 }
620 }
621
622
623
624 template <int dim, template <int, int> class MeshType, int spacedim>
626 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
627 unsigned int find_closest_vertex(const MeshType<dim, spacedim> &mesh,
628 const Point<spacedim> &p,
629 const std::vector<bool> &marked_vertices)
630 {
631 // first get the underlying triangulation from the mesh and determine
632 // vertices and used vertices
634
635 const std::vector<Point<spacedim>> &vertices = tria.get_vertices();
636
637 Assert(tria.get_vertices().size() == marked_vertices.size() ||
638 marked_vertices.empty(),
640 marked_vertices.size()));
641
642 // marked_vertices is expected to be a subset of used_vertices. Thus,
643 // comparing the range marked_vertices.begin() to marked_vertices.end() with
644 // the range used_vertices.begin() to used_vertices.end() the element in the
645 // second range must be valid if the element in the first range is valid.
646 Assert(
647 marked_vertices.empty() ||
648 std::equal(marked_vertices.begin(),
649 marked_vertices.end(),
650 tria.get_used_vertices().begin(),
651 [](bool p, bool q) { return !p || q; }),
653 "marked_vertices should be a subset of used vertices in the triangulation "
654 "but marked_vertices contains one or more vertices that are not used vertices!"));
655
656 // If marked_indices is empty, consider all used_vertices for finding the
657 // closest vertex to the point. Otherwise, marked_indices is used.
658 const std::vector<bool> &vertices_to_use =
659 (marked_vertices.empty()) ? tria.get_used_vertices() : marked_vertices;
660
661 // At the beginning, the first used vertex is considered to be the closest
662 // one.
663 std::vector<bool>::const_iterator first =
664 std::find(vertices_to_use.begin(), vertices_to_use.end(), true);
665
666 // Assert that at least one vertex is actually used
667 Assert(first != vertices_to_use.end(), ExcInternalError());
668
669 unsigned int best_vertex = std::distance(vertices_to_use.begin(), first);
670 double best_dist = (p - vertices[best_vertex]).norm_square();
671
672 // For all remaining vertices, test
673 // whether they are any closer
674 for (unsigned int j = best_vertex + 1; j < vertices.size(); ++j)
675 if (vertices_to_use[j])
676 {
677 const double dist = (p - vertices[j]).norm_square();
678 if (dist < best_dist)
679 {
680 best_vertex = j;
681 best_dist = dist;
682 }
683 }
684
685 return best_vertex;
686 }
687
688
689
690 template <int dim, template <int, int> class MeshType, int spacedim>
692 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
693 unsigned int find_closest_vertex(const Mapping<dim, spacedim> &mapping,
694 const MeshType<dim, spacedim> &mesh,
695 const Point<spacedim> &p,
696 const std::vector<bool> &marked_vertices)
697 {
698 // Take a shortcut in the simple case.
699 if (mapping.preserves_vertex_locations() == true)
700 return find_closest_vertex(mesh, p, marked_vertices);
701
702 // first get the underlying triangulation from the mesh and determine
703 // vertices and used vertices
705
706 auto vertices = extract_used_vertices(tria, mapping);
707
708 Assert(tria.get_vertices().size() == marked_vertices.size() ||
709 marked_vertices.empty(),
711 marked_vertices.size()));
712
713 // marked_vertices is expected to be a subset of used_vertices. Thus,
714 // comparing the range marked_vertices.begin() to marked_vertices.end()
715 // with the range used_vertices.begin() to used_vertices.end() the element
716 // in the second range must be valid if the element in the first range is
717 // valid.
718 Assert(
719 marked_vertices.empty() ||
720 std::equal(marked_vertices.begin(),
721 marked_vertices.end(),
722 tria.get_used_vertices().begin(),
723 [](bool p, bool q) { return !p || q; }),
725 "marked_vertices should be a subset of used vertices in the triangulation "
726 "but marked_vertices contains one or more vertices that are not used vertices!"));
727
728 // Remove from the map unwanted elements.
729 if (marked_vertices.size() != 0)
730 for (auto it = vertices.begin(); it != vertices.end();)
731 {
732 if (marked_vertices[it->first] == false)
733 {
734 it = vertices.erase(it);
735 }
736 else
737 {
738 ++it;
739 }
740 }
741
742 return find_closest_vertex(vertices, p);
743 }
744
745
746
747 template <int dim, int spacedim>
748 std::vector<std::vector<Tensor<1, spacedim>>>
751 const std::vector<
753 &vertex_to_cells)
754 {
755 const std::vector<Point<spacedim>> &vertices = mesh.get_vertices();
756 const unsigned int n_vertices = vertex_to_cells.size();
757
758 AssertDimension(vertices.size(), n_vertices);
759
760
761 std::vector<std::vector<Tensor<1, spacedim>>> vertex_to_cell_centers(
762 n_vertices);
763 for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
764 if (mesh.vertex_used(vertex))
765 {
766 const unsigned int n_neighbor_cells = vertex_to_cells[vertex].size();
767 vertex_to_cell_centers[vertex].resize(n_neighbor_cells);
768
769 typename std::set<typename Triangulation<dim, spacedim>::
770 active_cell_iterator>::iterator it =
771 vertex_to_cells[vertex].begin();
772 for (unsigned int cell = 0; cell < n_neighbor_cells; ++cell, ++it)
773 {
774 vertex_to_cell_centers[vertex][cell] =
775 (*it)->center() - vertices[vertex];
776 vertex_to_cell_centers[vertex][cell] /=
777 vertex_to_cell_centers[vertex][cell].norm();
778 }
779 }
780 return vertex_to_cell_centers;
781 }
782
783
784 namespace internal
785 {
786 template <int spacedim>
787 bool
789 const unsigned int a,
790 const unsigned int b,
791 const Tensor<1, spacedim> &point_direction,
792 const std::vector<Tensor<1, spacedim>> &center_directions)
793 {
794 const double scalar_product_a = center_directions[a] * point_direction;
795 const double scalar_product_b = center_directions[b] * point_direction;
796
797 // The function is supposed to return if a is before b. We are looking
798 // for the alignment of point direction and center direction, therefore
799 // return if the scalar product of a is larger.
800 return (scalar_product_a > scalar_product_b);
801 }
802 } // namespace internal
803
804 template <int dim, template <int, int> class MeshType, int spacedim>
806 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
807#ifndef _MSC_VER
808 std::pair<typename MeshType<dim, spacedim>::active_cell_iterator, Point<dim>>
809#else
810 std::pair<typename ::internal::
811 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type,
813#endif
815 const Mapping<dim, spacedim> &mapping,
816 const MeshType<dim, spacedim> &mesh,
817 const Point<spacedim> &p,
818 const std::vector<
819 std::set<typename MeshType<dim, spacedim>::active_cell_iterator>>
820 &vertex_to_cells,
821 const std::vector<std::vector<Tensor<1, spacedim>>>
822 &vertex_to_cell_centers,
823 const typename MeshType<dim, spacedim>::active_cell_iterator &cell_hint,
824 const std::vector<bool> &marked_vertices,
825 const RTree<std::pair<Point<spacedim>, unsigned int>>
826 &used_vertices_rtree,
827 const double tolerance,
828 const RTree<
829 std::pair<BoundingBox<spacedim>,
831 *relevant_cell_bounding_boxes_rtree)
832 {
833 std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
835 cell_and_position;
836 cell_and_position.first = mesh.end();
837
838 // To handle points at the border we keep track of points which are close to
839 // the unit cell:
840 std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
842 cell_and_position_approx;
843
844 if (relevant_cell_bounding_boxes_rtree != nullptr &&
845 !relevant_cell_bounding_boxes_rtree->empty())
846 {
847 // create a bounding box around point p with 2*tolerance as side length.
848 const auto bb = BoundingBox<spacedim>(p).create_extended(tolerance);
849
850 if (relevant_cell_bounding_boxes_rtree->qbegin(
851 boost::geometry::index::intersects(bb)) ==
852 relevant_cell_bounding_boxes_rtree->qend())
853 return cell_and_position;
854 }
855
856 bool found_cell = false;
857 bool approx_cell = false;
858
859 unsigned int closest_vertex_index = 0;
860 // ensure closest vertex index is a marked one, otherwise cell (with vertex
861 // 0) might be found even though it is not marked. This is only relevant if
862 // searching with rtree, using find_closest_vertex already can manage not
863 // finding points
864 if (marked_vertices.size() && !used_vertices_rtree.empty())
865 {
866 const auto itr =
867 std::find(marked_vertices.begin(), marked_vertices.end(), true);
868 Assert(itr != marked_vertices.end(),
869 ::ExcMessage("No vertex has been marked!"));
870 closest_vertex_index = std::distance(marked_vertices.begin(), itr);
871 }
872
873 Tensor<1, spacedim> vertex_to_point;
874 auto current_cell = cell_hint;
875
876 // check whether cell has at least one marked vertex
877 const auto cell_marked = [&mesh, &marked_vertices](const auto &cell) {
878 if (marked_vertices.empty())
879 return true;
880
881 if (cell != mesh.active_cell_iterators().end())
882 for (unsigned int i = 0; i < cell->n_vertices(); ++i)
883 if (marked_vertices[cell->vertex_index(i)])
884 return true;
885
886 return false;
887 };
888
889 // check whether any cell in collection is marked
890 const auto any_cell_marked = [&cell_marked](const auto &cells) {
891 return std::any_of(cells.begin(),
892 cells.end(),
893 [&cell_marked](const auto &cell) {
894 return cell_marked(cell);
895 });
896 };
897 (void)any_cell_marked;
898
899 while (found_cell == false)
900 {
901 // First look at the vertices of the cell cell_hint. If it's an
902 // invalid cell, then query for the closest global vertex
903 if (current_cell.state() == IteratorState::valid &&
904 cell_marked(cell_hint))
905 {
906 const auto cell_vertices = mapping.get_vertices(current_cell);
907 const unsigned int closest_vertex =
908 find_closest_vertex_of_cell<dim, spacedim>(current_cell,
909 p,
910 mapping);
911 vertex_to_point = p - cell_vertices[closest_vertex];
912 closest_vertex_index = current_cell->vertex_index(closest_vertex);
913 }
914 else
915 {
916 // For some clang-based compilers and boost versions the call to
917 // RTree::query doesn't compile. Since using an rtree here is just a
918 // performance improvement disabling this branch is OK.
919 // This is fixed in boost in
920 // https://github.com/boostorg/numeric_conversion/commit/50a1eae942effb0a9b90724323ef8f2a67e7984a
921#if defined(DEAL_II_WITH_BOOST_BUNDLED) || \
922 !(defined(__clang_major__) && __clang_major__ >= 16) || \
923 BOOST_VERSION >= 108100
924 if (!used_vertices_rtree.empty())
925 {
926 // If we have an rtree at our disposal, use it.
927 using ValueType = std::pair<Point<spacedim>, unsigned int>;
928 std::function<bool(const ValueType &)> marked;
929 if (marked_vertices.size() == mesh.n_vertices())
930 marked = [&marked_vertices](const ValueType &value) -> bool {
931 return marked_vertices[value.second];
932 };
933 else
934 marked = [](const ValueType &) -> bool { return true; };
935
936 std::vector<std::pair<Point<spacedim>, unsigned int>> res;
937 used_vertices_rtree.query(
938 boost::geometry::index::nearest(p, 1) &&
939 boost::geometry::index::satisfies(marked),
940 std::back_inserter(res));
941
942 // Searching for a point which is located outside the
943 // triangulation results in res.size() = 0
944 Assert(res.size() < 2,
945 ::ExcMessage("There can not be multiple results"));
946
947 if (res.size() > 0)
948 if (any_cell_marked(vertex_to_cells[res[0].second]))
949 closest_vertex_index = res[0].second;
950 }
951 else
952#endif
953 {
954 closest_vertex_index = GridTools::find_closest_vertex(
955 mapping, mesh, p, marked_vertices);
956 }
957 vertex_to_point = p - mesh.get_vertices()[closest_vertex_index];
958 }
959
960 if constexpr (running_in_debug_mode())
961 {
962 {
963 // Double-check if found index is at marked cell
964 Assert(any_cell_marked(vertex_to_cells[closest_vertex_index]),
965 ::ExcMessage("Found non-marked vertex"));
966 }
967 }
968
969 const double vertex_point_norm = vertex_to_point.norm();
970 if (vertex_point_norm > 0)
971 vertex_to_point /= vertex_point_norm;
972
973 const unsigned int n_neighbor_cells =
974 vertex_to_cells[closest_vertex_index].size();
975
976 // Create a corresponding map of vectors from vertex to cell center
977 std::vector<unsigned int> neighbor_permutation(n_neighbor_cells);
978
979 for (unsigned int i = 0; i < n_neighbor_cells; ++i)
980 neighbor_permutation[i] = i;
981
982 auto comp = [&](const unsigned int a, const unsigned int b) -> bool {
983 return internal::compare_point_association<spacedim>(
984 a,
985 b,
986 vertex_to_point,
987 vertex_to_cell_centers[closest_vertex_index]);
988 };
989
990 std::sort(neighbor_permutation.begin(),
991 neighbor_permutation.end(),
992 comp);
993 // It is possible the vertex is close
994 // to an edge, thus we add a tolerance
995 // to keep also the "best" cell
996 double best_distance = tolerance;
997
998 // Search all of the cells adjacent to the closest vertex of the cell
999 // hint. Most likely we will find the point in them.
1000 for (unsigned int i = 0; i < n_neighbor_cells; ++i)
1001 {
1002 try
1003 {
1004 auto cell = vertex_to_cells[closest_vertex_index].begin();
1005 std::advance(cell, neighbor_permutation[i]);
1006
1007 if (!(*cell)->is_artificial())
1008 {
1009 const Point<dim> p_unit =
1010 mapping.transform_real_to_unit_cell(*cell, p);
1011 if ((*cell)->reference_cell().contains_point(p_unit,
1012 tolerance))
1013 {
1014 cell_and_position.first = *cell;
1015 cell_and_position.second = p_unit;
1016 found_cell = true;
1017 approx_cell = false;
1018 break;
1019 }
1020 // The point is not inside this cell: checking how far
1021 // outside it is and whether we want to use this cell as a
1022 // backup if we can't find a cell within which the point
1023 // lies.
1024 const double dist = p_unit.distance(
1025 (*cell)->reference_cell().closest_point(p_unit));
1026 if (dist < best_distance)
1027 {
1028 best_distance = dist;
1029 cell_and_position_approx.first = *cell;
1030 cell_and_position_approx.second = p_unit;
1031 approx_cell = true;
1032 }
1033 }
1034 }
1035 catch (typename Mapping<dim>::ExcTransformationFailed &)
1036 {}
1037 }
1038
1039 if (found_cell == true)
1040 return cell_and_position;
1041 else if (approx_cell == true)
1042 return cell_and_position_approx;
1043
1044 // The first time around, we check for vertices in the hint_cell. If
1045 // that does not work, we set the cell iterator to an invalid one, and
1046 // look for a global vertex close to the point. If that does not work,
1047 // we are in trouble, and just throw an exception.
1048 //
1049 // If we got here, then we did not find the point. If the
1050 // current_cell.state() here is not IteratorState::valid, it means that
1051 // the user did not provide a hint_cell, and at the beginning of the
1052 // while loop we performed an actual global search on the mesh
1053 // vertices. Not finding the point then means the point is outside the
1054 // domain, or that we've had problems with the algorithm above. Try as a
1055 // last resort the other (simpler) algorithm.
1056 if (current_cell.state() != IteratorState::valid)
1058 mapping, mesh, p, marked_vertices, tolerance);
1059
1060 current_cell = typename MeshType<dim, spacedim>::active_cell_iterator();
1061 }
1062 return cell_and_position;
1063 }
1064
1065
1066
1067 template <int dim, int spacedim>
1068 unsigned int
1071 const Point<spacedim> &position,
1072 const Mapping<dim, spacedim> &mapping)
1073 {
1074 const auto vertices = mapping.get_vertices(cell);
1075 double minimum_distance = position.distance_square(vertices[0]);
1076 unsigned int closest_vertex = 0;
1077 const unsigned int n_vertices = cell->n_vertices();
1078
1079 for (unsigned int v = 1; v < n_vertices; ++v)
1080 {
1081 const double vertex_distance = position.distance_square(vertices[v]);
1082 if (vertex_distance < minimum_distance)
1083 {
1084 closest_vertex = v;
1085 minimum_distance = vertex_distance;
1086 }
1087 }
1088 return closest_vertex;
1089 }
1090
1091
1092
1093 namespace internal
1094 {
1095 namespace BoundingBoxPredicate
1096 {
1097 template <typename MeshType>
1100 std::tuple<
1102 bool> compute_cell_predicate_bounding_box(const typename MeshType::
1103 cell_iterator &parent_cell,
1104 const std::function<bool(
1105 const typename MeshType::
1106 active_cell_iterator &)>
1107 &predicate)
1108 {
1109 bool has_predicate =
1110 false; // Start assuming there's no cells with predicate inside
1111 std::vector<typename MeshType::active_cell_iterator> active_cells;
1112 if (parent_cell->is_active())
1113 active_cells = {parent_cell};
1114 else
1115 // Finding all active cells descendants of the current one (or the
1116 // current one if it is active)
1117 active_cells = get_active_child_cells<MeshType>(parent_cell);
1118
1119 const unsigned int spacedim = MeshType::space_dimension;
1120
1121 // Looking for the first active cell which has the property predicate
1122 unsigned int i = 0;
1123 while (i < active_cells.size() && !predicate(active_cells[i]))
1124 ++i;
1125
1126 // No active cells or no active cells with property
1127 if (active_cells.empty() || i == active_cells.size())
1128 {
1130 return std::make_tuple(bbox, has_predicate);
1131 }
1132
1133 // The two boundary points defining the boundary box
1134 Point<spacedim> maxp = active_cells[i]->vertex(0);
1135 Point<spacedim> minp = active_cells[i]->vertex(0);
1136
1137 for (; i < active_cells.size(); ++i)
1138 if (predicate(active_cells[i]))
1139 for (const unsigned int v : active_cells[i]->vertex_indices())
1140 for (unsigned int d = 0; d < spacedim; ++d)
1141 {
1142 minp[d] = std::min(minp[d], active_cells[i]->vertex(v)[d]);
1143 maxp[d] = std::max(maxp[d], active_cells[i]->vertex(v)[d]);
1144 }
1145
1146 has_predicate = true;
1147 BoundingBox<spacedim> bbox(std::make_pair(minp, maxp));
1148 return std::make_tuple(bbox, has_predicate);
1149 }
1150 } // namespace BoundingBoxPredicate
1151 } // namespace internal
1152
1153
1154
1155 template <typename MeshType>
1157 std::
1158 vector<BoundingBox<MeshType::space_dimension>> compute_mesh_predicate_bounding_box(
1159 const MeshType &mesh,
1160 const std::function<bool(const typename MeshType::active_cell_iterator &)>
1161 &predicate,
1162 const unsigned int refinement_level,
1163 const bool allow_merge,
1164 const unsigned int max_boxes)
1165 {
1166 // Algorithm brief description: begin with creating bounding boxes of all
1167 // cells at refinement_level (and coarser levels if there are active cells)
1168 // which have the predicate property. These are then merged
1169
1170 Assert(
1171 refinement_level <= mesh.n_levels(),
1172 ExcMessage(
1173 "Error: refinement level is higher then total levels in the triangulation!"));
1174
1175 const unsigned int spacedim = MeshType::space_dimension;
1176 std::vector<BoundingBox<spacedim>> bounding_boxes;
1177
1178 // Creating a bounding box for all active cell on coarser level
1179
1180 for (unsigned int i = 0; i < refinement_level; ++i)
1181 for (const typename MeshType::cell_iterator &cell :
1182 mesh.active_cell_iterators_on_level(i))
1183 {
1184 bool has_predicate = false;
1186 std::tie(bbox, has_predicate) =
1188 MeshType>(cell, predicate);
1189 if (has_predicate)
1190 bounding_boxes.push_back(bbox);
1191 }
1192
1193 // Creating a Bounding Box for all cells on the chosen refinement_level
1194 for (const typename MeshType::cell_iterator &cell :
1195 mesh.cell_iterators_on_level(refinement_level))
1196 {
1197 bool has_predicate = false;
1199 std::tie(bbox, has_predicate) =
1201 MeshType>(cell, predicate);
1202 if (has_predicate)
1203 bounding_boxes.push_back(bbox);
1204 }
1205
1206 if (!allow_merge)
1207 // If merging is not requested return the created bounding_boxes
1208 return bounding_boxes;
1209 else
1210 {
1211 // Merging part of the algorithm
1212 // Part 1: merging neighbors
1213 // This array stores the indices of arrays we have already merged
1214 std::vector<unsigned int> merged_boxes_idx;
1215 bool found_neighbors = true;
1216
1217 // We merge only neighbors which can be expressed by a single bounding
1218 // box e.g. in 1d [0,1] and [1,2] can be described with [0,2] without
1219 // losing anything
1220 while (found_neighbors)
1221 {
1222 found_neighbors = false;
1223 for (unsigned int i = 0; i < bounding_boxes.size() - 1; ++i)
1224 {
1225 if (std::find(merged_boxes_idx.begin(),
1226 merged_boxes_idx.end(),
1227 i) == merged_boxes_idx.end())
1228 for (unsigned int j = i + 1; j < bounding_boxes.size(); ++j)
1229 if (std::find(merged_boxes_idx.begin(),
1230 merged_boxes_idx.end(),
1231 j) == merged_boxes_idx.end() &&
1232 bounding_boxes[i].get_neighbor_type(
1233 bounding_boxes[j]) ==
1235 {
1236 bounding_boxes[i].merge_with(bounding_boxes[j]);
1237 merged_boxes_idx.push_back(j);
1238 found_neighbors = true;
1239 }
1240 }
1241 }
1242
1243 // Copying the merged boxes into merged_b_boxes
1244 std::vector<BoundingBox<spacedim>> merged_b_boxes;
1245 for (unsigned int i = 0; i < bounding_boxes.size(); ++i)
1246 if (std::find(merged_boxes_idx.begin(), merged_boxes_idx.end(), i) ==
1247 merged_boxes_idx.end())
1248 merged_b_boxes.push_back(bounding_boxes[i]);
1249
1250 // Part 2: if there are too many bounding boxes, merging smaller boxes
1251 // This has sense only in dimension 2 or greater, since in dimension 1,
1252 // neighboring intervals can always be merged without problems
1253 if ((merged_b_boxes.size() > max_boxes) && (spacedim > 1))
1254 {
1255 std::vector<double> volumes;
1256 volumes.reserve(merged_b_boxes.size());
1257 for (unsigned int i = 0; i < merged_b_boxes.size(); ++i)
1258 volumes.push_back(merged_b_boxes[i].volume());
1259
1260 while (merged_b_boxes.size() > max_boxes)
1261 {
1262 unsigned int min_idx =
1263 std::min_element(volumes.begin(), volumes.end()) -
1264 volumes.begin();
1265 volumes.erase(volumes.begin() + min_idx);
1266 // Finding a neighbor
1267 bool not_removed = true;
1268 for (unsigned int i = 0;
1269 i < merged_b_boxes.size() && not_removed;
1270 ++i)
1271 // We merge boxes if we have "attached" or "mergeable"
1272 // neighbors, even though mergeable should be dealt with in
1273 // Part 1
1274 if (i != min_idx && (merged_b_boxes[i].get_neighbor_type(
1275 merged_b_boxes[min_idx]) ==
1277 merged_b_boxes[i].get_neighbor_type(
1278 merged_b_boxes[min_idx]) ==
1280 {
1281 merged_b_boxes[i].merge_with(merged_b_boxes[min_idx]);
1282 merged_b_boxes.erase(merged_b_boxes.begin() + min_idx);
1283 not_removed = false;
1284 }
1285 Assert(!not_removed,
1286 ExcMessage("Error: couldn't merge bounding boxes!"));
1287 }
1288 }
1289 Assert(merged_b_boxes.size() <= max_boxes,
1290 ExcMessage(
1291 "Error: couldn't reach target number of bounding boxes!"));
1292 return merged_b_boxes;
1293 }
1294 }
1295
1296
1297
1298 template <int spacedim>
1299#ifndef DOXYGEN
1300 std::tuple<std::vector<std::vector<unsigned int>>,
1301 std::map<unsigned int, unsigned int>,
1302 std::map<unsigned int, std::vector<unsigned int>>>
1303#else
1304 return_type
1305#endif
1307 const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
1308 const std::vector<Point<spacedim>> &points)
1309 {
1310 unsigned int n_procs = global_bboxes.size();
1311 std::vector<std::vector<unsigned int>> point_owners(n_procs);
1312 std::map<unsigned int, unsigned int> map_owners_found;
1313 std::map<unsigned int, std::vector<unsigned int>> map_owners_guessed;
1314
1315 unsigned int n_points = points.size();
1316 for (unsigned int pt = 0; pt < n_points; ++pt)
1317 {
1318 // Keep track of how many processes we guess to own the point
1319 std::vector<unsigned int> owners_found;
1320 // Check in which other processes the point might be
1321 for (unsigned int rk = 0; rk < n_procs; ++rk)
1322 {
1323 for (const BoundingBox<spacedim> &bbox : global_bboxes[rk])
1324 if (bbox.point_inside(points[pt]))
1325 {
1326 point_owners[rk].emplace_back(pt);
1327 owners_found.emplace_back(rk);
1328 break; // We can check now the next process
1329 }
1330 }
1331 Assert(owners_found.size() > 0,
1332 ExcMessage("No owners found for the point " +
1333 std::to_string(pt)));
1334 if (owners_found.size() == 1)
1335 map_owners_found[pt] = owners_found[0];
1336 else
1337 // Multiple owners
1338 map_owners_guessed[pt] = owners_found;
1339 }
1340
1341 return std::make_tuple(std::move(point_owners),
1342 std::move(map_owners_found),
1343 std::move(map_owners_guessed));
1344 }
1345
1346 template <int spacedim>
1347#ifndef DOXYGEN
1348 std::tuple<std::map<unsigned int, std::vector<unsigned int>>,
1349 std::map<unsigned int, unsigned int>,
1350 std::map<unsigned int, std::vector<unsigned int>>>
1351#else
1352 return_type
1353#endif
1355 const RTree<std::pair<BoundingBox<spacedim>, unsigned int>> &covering_rtree,
1356 const std::vector<Point<spacedim>> &points)
1357 {
1358 std::map<unsigned int, std::vector<unsigned int>> point_owners;
1359 std::map<unsigned int, unsigned int> map_owners_found;
1360 std::map<unsigned int, std::vector<unsigned int>> map_owners_guessed;
1361 std::vector<std::pair<BoundingBox<spacedim>, unsigned int>> search_result;
1362
1363 unsigned int n_points = points.size();
1364 for (unsigned int pt_n = 0; pt_n < n_points; ++pt_n)
1365 {
1366 search_result.clear(); // clearing last output
1367
1368 // Running tree search
1369 covering_rtree.query(boost::geometry::index::intersects(points[pt_n]),
1370 std::back_inserter(search_result));
1371
1372 // Keep track of how many processes we guess to own the point
1373 std::set<unsigned int> owners_found;
1374 // Check in which other processes the point might be
1375 for (const auto &rank_bbox : search_result)
1376 {
1377 // Try to add the owner to the owners found,
1378 // and check if it was already present
1379 const bool pt_inserted = owners_found.insert(pt_n).second;
1380 if (pt_inserted)
1381 point_owners[rank_bbox.second].emplace_back(pt_n);
1382 }
1383 Assert(owners_found.size() > 0,
1384 ExcMessage("No owners found for the point " +
1385 std::to_string(pt_n)));
1386 if (owners_found.size() == 1)
1387 map_owners_found[pt_n] = *owners_found.begin();
1388 else
1389 // Multiple owners
1390 std::copy(owners_found.begin(),
1391 owners_found.end(),
1392 std::back_inserter(map_owners_guessed[pt_n]));
1393 }
1394
1395 return std::make_tuple(std::move(point_owners),
1396 std::move(map_owners_found),
1397 std::move(map_owners_guessed));
1398 }
1399
1400
1401
1402 template <int dim, int spacedim>
1403 std::map<unsigned int, types::global_vertex_index>
1405 const Triangulation<dim, spacedim> &triangulation)
1406 {
1407 std::map<unsigned int, types::global_vertex_index>
1408 local_to_global_vertex_index;
1409
1410#ifndef DEAL_II_WITH_MPI
1411
1412 // If we don't have MPI then all vertices are local
1413 for (unsigned int i = 0; i < triangulation.n_vertices(); ++i)
1414 local_to_global_vertex_index[i] = i;
1415
1416#else
1417
1418 using active_cell_iterator =
1420 const std::vector<std::set<active_cell_iterator>> vertex_to_cell =
1421 vertex_to_cell_map(triangulation);
1422
1423 // Create a local index for the locally "owned" vertices
1424 types::global_vertex_index next_index = 0;
1425 unsigned int max_cellid_size = 0;
1426 std::set<std::pair<types::subdomain_id, types::global_vertex_index>>
1427 vertices_added;
1428 std::map<types::subdomain_id, std::set<unsigned int>> vertices_to_recv;
1429 std::map<types::subdomain_id,
1430 std::vector<std::tuple<types::global_vertex_index,
1432 std::string>>>
1433 vertices_to_send;
1434 std::set<active_cell_iterator> missing_vert_cells;
1435 std::set<unsigned int> used_vertex_index;
1436 for (const auto &cell : triangulation.active_cell_iterators())
1437 {
1438 if (cell->is_locally_owned())
1439 {
1440 for (const unsigned int i : cell->vertex_indices())
1441 {
1442 types::subdomain_id lowest_subdomain_id = cell->subdomain_id();
1443 for (const auto &adjacent_cell :
1444 vertex_to_cell[cell->vertex_index(i)])
1445 lowest_subdomain_id = std::min(lowest_subdomain_id,
1446 adjacent_cell->subdomain_id());
1447
1448 // See if this process "owns" this vertex
1449 if (lowest_subdomain_id == cell->subdomain_id())
1450 {
1451 // Check that the vertex we are working on is a vertex that
1452 // has not been dealt with yet
1453 if (used_vertex_index.find(cell->vertex_index(i)) ==
1454 used_vertex_index.end())
1455 {
1456 // Set the local index
1457 local_to_global_vertex_index[cell->vertex_index(i)] =
1458 next_index++;
1459
1460 // Store the information that will be sent to the
1461 // adjacent cells on other subdomains
1462 for (const auto &adjacent_cell :
1463 vertex_to_cell[cell->vertex_index(i)])
1464 if (adjacent_cell->subdomain_id() !=
1465 cell->subdomain_id())
1466 {
1467 std::pair<types::subdomain_id,
1469 tmp(adjacent_cell->subdomain_id(),
1470 cell->vertex_index(i));
1471 if (vertices_added.find(tmp) ==
1472 vertices_added.end())
1473 {
1474 vertices_to_send[adjacent_cell
1475 ->subdomain_id()]
1476 .emplace_back(i,
1477 cell->vertex_index(i),
1478 cell->id().to_string());
1479 if (cell->id().to_string().size() >
1480 max_cellid_size)
1481 max_cellid_size =
1482 cell->id().to_string().size();
1483 vertices_added.insert(tmp);
1484 }
1485 }
1486 used_vertex_index.insert(cell->vertex_index(i));
1487 }
1488 }
1489 else
1490 {
1491 // We don't own the vertex so we will receive its global
1492 // index
1493 vertices_to_recv[lowest_subdomain_id].insert(
1494 cell->vertex_index(i));
1495 missing_vert_cells.insert(cell);
1496 }
1497 }
1498 }
1499
1500 // Some hanging nodes are vertices of ghost cells. They need to be
1501 // received.
1502 if (cell->is_ghost())
1503 {
1504 for (const unsigned int i : cell->face_indices())
1505 {
1506 if (cell->at_boundary(i) == false)
1507 {
1508 if (cell->neighbor(i)->is_active())
1509 {
1510 typename Triangulation<dim,
1511 spacedim>::active_cell_iterator
1512 adjacent_cell = cell->neighbor(i);
1513 if ((adjacent_cell->is_locally_owned()))
1514 {
1515 types::subdomain_id adj_subdomain_id =
1516 adjacent_cell->subdomain_id();
1517 if (cell->subdomain_id() < adj_subdomain_id)
1518 for (unsigned int j = 0;
1519 j < cell->face(i)->n_vertices();
1520 ++j)
1521 {
1522 vertices_to_recv[cell->subdomain_id()].insert(
1523 cell->face(i)->vertex_index(j));
1524 missing_vert_cells.insert(cell);
1525 }
1526 }
1527 }
1528 }
1529 }
1530 }
1531 }
1532
1533 // Get the size of the largest CellID string
1534 max_cellid_size = Utilities::MPI::max(max_cellid_size,
1535 triangulation.get_mpi_communicator());
1536
1537 // Make indices global by getting the number of vertices owned by each
1538 // processors and shifting the indices accordingly
1540 int ierr = MPI_Exscan(
1541 &next_index,
1542 &shift,
1543 1,
1544 Utilities::MPI::mpi_type_id_for_type<types::global_vertex_index>,
1545 MPI_SUM,
1546 triangulation.get_mpi_communicator());
1547 AssertThrowMPI(ierr);
1548
1549 for (auto &global_index_it : local_to_global_vertex_index)
1550 global_index_it.second += shift;
1551
1552
1553 const int mpi_tag = Utilities::MPI::internal::Tags::
1555 const int mpi_tag2 = Utilities::MPI::internal::Tags::
1557
1558
1559 // In a first message, send the global ID of the vertices and the local
1560 // positions in the cells. In a second messages, send the cell ID as a
1561 // resize string. This is done in two messages so that types are not mixed
1562
1563 // Send the first message
1564 std::vector<std::vector<types::global_vertex_index>> vertices_send_buffers(
1565 vertices_to_send.size());
1566 std::vector<MPI_Request> first_requests(vertices_to_send.size());
1567 typename std::map<types::subdomain_id,
1568 std::vector<std::tuple<types::global_vertex_index,
1570 std::string>>>::iterator
1571 vert_to_send_it = vertices_to_send.begin(),
1572 vert_to_send_end = vertices_to_send.end();
1573 for (unsigned int i = 0; vert_to_send_it != vert_to_send_end;
1574 ++vert_to_send_it, ++i)
1575 {
1576 int destination = vert_to_send_it->first;
1577 const unsigned int n_vertices = vert_to_send_it->second.size();
1578 const int buffer_size = 2 * n_vertices;
1579 vertices_send_buffers[i].resize(buffer_size);
1580
1581 // fill the buffer
1582 for (unsigned int j = 0; j < n_vertices; ++j)
1583 {
1584 vertices_send_buffers[i][2 * j] =
1585 std::get<0>(vert_to_send_it->second[j]);
1586 vertices_send_buffers[i][2 * j + 1] =
1587 local_to_global_vertex_index[std::get<1>(
1588 vert_to_send_it->second[j])];
1589 }
1590
1591 // Send the message
1592 ierr = MPI_Isend(
1593 vertices_send_buffers[i].data(),
1594 buffer_size,
1595 Utilities::MPI::mpi_type_id_for_type<types::global_vertex_index>,
1596 destination,
1597 mpi_tag,
1598 triangulation.get_mpi_communicator(),
1599 &first_requests[i]);
1600 AssertThrowMPI(ierr);
1601 }
1602
1603 // Receive the first message
1604 std::vector<std::vector<types::global_vertex_index>> vertices_recv_buffers(
1605 vertices_to_recv.size());
1606 typename std::map<types::subdomain_id, std::set<unsigned int>>::iterator
1607 vert_to_recv_it = vertices_to_recv.begin(),
1608 vert_to_recv_end = vertices_to_recv.end();
1609 for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
1610 ++vert_to_recv_it, ++i)
1611 {
1612 int source = vert_to_recv_it->first;
1613 const unsigned int n_vertices = vert_to_recv_it->second.size();
1614 const int buffer_size = 2 * n_vertices;
1615 vertices_recv_buffers[i].resize(buffer_size);
1616
1617 // Receive the message
1618 ierr = MPI_Recv(
1619 vertices_recv_buffers[i].data(),
1620 buffer_size,
1621 Utilities::MPI::mpi_type_id_for_type<types::global_vertex_index>,
1622 source,
1623 mpi_tag,
1624 triangulation.get_mpi_communicator(),
1625 MPI_STATUS_IGNORE);
1626 AssertThrowMPI(ierr);
1627 }
1628
1629 // At this point, wait for all of the isend operations to finish:
1630 MPI_Waitall(first_requests.size(),
1631 first_requests.data(),
1632 MPI_STATUSES_IGNORE);
1633
1634
1635 // Send second message
1636 std::vector<std::vector<char>> cellids_send_buffers(
1637 vertices_to_send.size());
1638 std::vector<MPI_Request> second_requests(vertices_to_send.size());
1639 vert_to_send_it = vertices_to_send.begin();
1640 for (unsigned int i = 0; vert_to_send_it != vert_to_send_end;
1641 ++vert_to_send_it, ++i)
1642 {
1643 int destination = vert_to_send_it->first;
1644 const unsigned int n_vertices = vert_to_send_it->second.size();
1645 const int buffer_size = max_cellid_size * n_vertices;
1646 cellids_send_buffers[i].resize(buffer_size);
1647
1648 // fill the buffer
1649 unsigned int pos = 0;
1650 for (unsigned int j = 0; j < n_vertices; ++j)
1651 {
1652 std::string cell_id = std::get<2>(vert_to_send_it->second[j]);
1653 for (unsigned int k = 0; k < max_cellid_size; ++k, ++pos)
1654 {
1655 if (k < cell_id.size())
1656 cellids_send_buffers[i][pos] = cell_id[k];
1657 // if necessary fill up the reserved part of the buffer with an
1658 // invalid value
1659 else
1660 cellids_send_buffers[i][pos] = '-';
1661 }
1662 }
1663
1664 // Send the message
1665 ierr = MPI_Isend(cellids_send_buffers[i].data(),
1666 buffer_size,
1667 MPI_CHAR,
1668 destination,
1669 mpi_tag2,
1670 triangulation.get_mpi_communicator(),
1671 &second_requests[i]);
1672 AssertThrowMPI(ierr);
1673 }
1674
1675 // Receive the second message
1676 std::vector<std::vector<char>> cellids_recv_buffers(
1677 vertices_to_recv.size());
1678 vert_to_recv_it = vertices_to_recv.begin();
1679 for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
1680 ++vert_to_recv_it, ++i)
1681 {
1682 int source = vert_to_recv_it->first;
1683 const unsigned int n_vertices = vert_to_recv_it->second.size();
1684 const int buffer_size = max_cellid_size * n_vertices;
1685 cellids_recv_buffers[i].resize(buffer_size);
1686
1687 // Receive the message
1688 ierr = MPI_Recv(cellids_recv_buffers[i].data(),
1689 buffer_size,
1690 MPI_CHAR,
1691 source,
1692 mpi_tag2,
1693 triangulation.get_mpi_communicator(),
1694 MPI_STATUS_IGNORE);
1695 AssertThrowMPI(ierr);
1696 }
1697
1698
1699 // Match the data received with the required vertices
1700 vert_to_recv_it = vertices_to_recv.begin();
1701 for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
1702 ++i, ++vert_to_recv_it)
1703 {
1704 for (unsigned int j = 0; j < vert_to_recv_it->second.size(); ++j)
1705 {
1706 const unsigned int local_pos_recv = vertices_recv_buffers[i][2 * j];
1707 const types::global_vertex_index global_id_recv =
1708 vertices_recv_buffers[i][2 * j + 1];
1709 const std::string cellid_recv(
1710 &cellids_recv_buffers[i][max_cellid_size * j],
1711 &cellids_recv_buffers[i][max_cellid_size * j] + max_cellid_size);
1712 bool found = false;
1713 typename std::set<active_cell_iterator>::iterator
1714 cell_set_it = missing_vert_cells.begin(),
1715 end_cell_set = missing_vert_cells.end();
1716 for (; (found == false) && (cell_set_it != end_cell_set);
1717 ++cell_set_it)
1718 {
1719 typename std::set<active_cell_iterator>::iterator
1720 candidate_cell =
1721 vertex_to_cell[(*cell_set_it)->vertex_index(i)].begin(),
1722 end_cell =
1723 vertex_to_cell[(*cell_set_it)->vertex_index(i)].end();
1724 for (; candidate_cell != end_cell; ++candidate_cell)
1725 {
1726 std::string current_cellid =
1727 (*candidate_cell)->id().to_string();
1728 current_cellid.resize(max_cellid_size, '-');
1729 if (current_cellid.compare(cellid_recv) == 0)
1730 {
1731 local_to_global_vertex_index
1732 [(*candidate_cell)->vertex_index(local_pos_recv)] =
1733 global_id_recv;
1734 found = true;
1735
1736 break;
1737 }
1738 }
1739 }
1740 }
1741 }
1742
1743 // At this point, wait for all of the isend operations of the second round
1744 // to finish:
1745 MPI_Waitall(second_requests.size(),
1746 second_requests.data(),
1747 MPI_STATUSES_IGNORE);
1748#endif
1749
1750 return local_to_global_vertex_index;
1751 }
1752
1753
1754
1755 template <int dim, int spacedim>
1756 std::vector<types::global_vertex_index>
1758 const Triangulation<dim, spacedim> &serial_tria,
1759 const Triangulation<dim, spacedim> &parallel_tria)
1760 {
1761 AssertDimension(serial_tria.n_active_cells(),
1762 parallel_tria.n_global_active_cells());
1763
1764 const auto locally_owned_indices =
1766 std::vector<types::global_vertex_index> vertex_map(
1767 parallel_tria.n_vertices(), numbers::invalid_unsigned_int);
1768
1769 // Assumption: serial and parallel meshes have the same ordering of cells.
1770 auto parallel_cell = parallel_tria.begin_active();
1771 for (; parallel_cell != parallel_tria.end(); ++parallel_cell)
1772 if (parallel_cell->is_locally_owned())
1773 {
1774 const auto serial_cell =
1775 serial_tria.create_cell_iterator(parallel_cell->id());
1776 for (const unsigned int &v : serial_cell->vertex_indices())
1777 {
1778 const auto serial_index = serial_cell->vertex_index(v);
1779 const auto parallel_index = parallel_cell->vertex_index(v);
1780 if (locally_owned_indices[parallel_index])
1781 vertex_map[parallel_index] = serial_index;
1782 }
1783 }
1784 return vertex_map;
1785 }
1786
1787
1788
1789 template <int dim, int spacedim>
1790 void
1791 partition_triangulation(const unsigned int n_partitions,
1792 Triangulation<dim, spacedim> &triangulation,
1793 const SparsityTools::Partitioner partitioner)
1794 {
1796 &triangulation) == nullptr),
1797 ExcMessage("Objects of type parallel::distributed::Triangulation "
1798 "are already partitioned implicitly and can not be "
1799 "partitioned again explicitly."));
1800
1801 std::vector<unsigned int> cell_weights;
1802
1803 // Get cell weighting if a signal has been attached to the triangulation
1804 if (!triangulation.signals.weight.empty())
1805 {
1806 cell_weights.resize(triangulation.n_active_cells(), 0U);
1807
1808 // In a first step, obtain the weights of the locally owned
1809 // cells. For all others, the weight remains at the zero the
1810 // vector was initialized with above.
1811 for (const auto &cell : triangulation.active_cell_iterators())
1812 if (cell->is_locally_owned())
1813 cell_weights[cell->active_cell_index()] =
1814 triangulation.signals.weight(cell, CellStatus::cell_will_persist);
1815
1816 // If this is a parallel triangulation, we then need to also
1817 // get the weights for all other cells. We have asserted above
1818 // that this function can't be used for
1819 // parallel::distributed::Triangulation objects, so the only
1820 // ones we have to worry about here are
1821 // parallel::shared::Triangulation
1822 if (const auto shared_tria =
1824 &triangulation))
1825 Utilities::MPI::sum(cell_weights,
1826 shared_tria->get_mpi_communicator(),
1827 cell_weights);
1828
1829 // verify that the global sum of weights is larger than 0
1830 Assert(std::accumulate(cell_weights.begin(),
1831 cell_weights.end(),
1832 std::uint64_t(0)) > 0,
1833 ExcMessage("The global sum of weights over all active cells "
1834 "is zero. Please verify how you generate weights."));
1835 }
1836
1837 // Call the other more general function
1838 partition_triangulation(n_partitions,
1839 cell_weights,
1840 triangulation,
1841 partitioner);
1842 }
1843
1844
1845
1846 template <int dim, int spacedim>
1847 void
1848 partition_triangulation(const unsigned int n_partitions,
1849 const std::vector<unsigned int> &cell_weights,
1850 Triangulation<dim, spacedim> &triangulation,
1851 const SparsityTools::Partitioner partitioner)
1852 {
1854 &triangulation) == nullptr),
1855 ExcMessage("Objects of type parallel::distributed::Triangulation "
1856 "are already partitioned implicitly and can not be "
1857 "partitioned again explicitly."));
1858 Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
1859
1860 // check for an easy return
1861 if (n_partitions == 1)
1862 {
1863 for (const auto &cell : triangulation.active_cell_iterators())
1864 cell->set_subdomain_id(0);
1865 return;
1866 }
1867
1868 // we decompose the domain by first
1869 // generating the connection graph of all
1870 // cells with their neighbors, and then
1871 // passing this graph off to METIS.
1872 // finally defer to the other function for
1873 // partitioning and assigning subdomain ids
1874 DynamicSparsityPattern cell_connectivity;
1875 get_face_connectivity_of_cells(triangulation, cell_connectivity);
1876
1877 SparsityPattern sp_cell_connectivity;
1878 sp_cell_connectivity.copy_from(cell_connectivity);
1879 partition_triangulation(n_partitions,
1880 cell_weights,
1881 sp_cell_connectivity,
1882 triangulation,
1883 partitioner);
1884 }
1885
1886
1887
1888 template <int dim, int spacedim>
1889 void
1890 partition_triangulation(const unsigned int n_partitions,
1891 const SparsityPattern &cell_connection_graph,
1892 Triangulation<dim, spacedim> &triangulation,
1893 const SparsityTools::Partitioner partitioner)
1894 {
1896 &triangulation) == nullptr),
1897 ExcMessage("Objects of type parallel::distributed::Triangulation "
1898 "are already partitioned implicitly and can not be "
1899 "partitioned again explicitly."));
1900
1901 std::vector<unsigned int> cell_weights;
1902
1903 // Get cell weighting if a signal has been attached to the triangulation
1904 if (!triangulation.signals.weight.empty())
1905 {
1906 cell_weights.resize(triangulation.n_active_cells(), 0U);
1907
1908 // In a first step, obtain the weights of the locally owned
1909 // cells. For all others, the weight remains at the zero the
1910 // vector was initialized with above.
1911 for (const auto &cell : triangulation.active_cell_iterators() |
1913 cell_weights[cell->active_cell_index()] =
1914 triangulation.signals.weight(cell, CellStatus::cell_will_persist);
1915
1916 // If this is a parallel triangulation, we then need to also
1917 // get the weights for all other cells. We have asserted above
1918 // that this function can't be used for
1919 // parallel::distribute::Triangulation objects, so the only
1920 // ones we have to worry about here are
1921 // parallel::shared::Triangulation
1922 if (const auto shared_tria =
1924 &triangulation))
1925 Utilities::MPI::sum(cell_weights,
1926 shared_tria->get_mpi_communicator(),
1927 cell_weights);
1928
1929 // verify that the global sum of weights is larger than 0
1930 Assert(std::accumulate(cell_weights.begin(),
1931 cell_weights.end(),
1932 std::uint64_t(0)) > 0,
1933 ExcMessage("The global sum of weights over all active cells "
1934 "is zero. Please verify how you generate weights."));
1935 }
1936
1937 // Call the other more general function
1938 partition_triangulation(n_partitions,
1939 cell_weights,
1940 cell_connection_graph,
1941 triangulation,
1942 partitioner);
1943 }
1944
1945
1946
1947 template <int dim, int spacedim>
1948 void
1949 partition_triangulation(const unsigned int n_partitions,
1950 const std::vector<unsigned int> &cell_weights,
1951 const SparsityPattern &cell_connection_graph,
1952 Triangulation<dim, spacedim> &triangulation,
1953 const SparsityTools::Partitioner partitioner)
1954 {
1956 &triangulation) == nullptr),
1957 ExcMessage("Objects of type parallel::distributed::Triangulation "
1958 "are already partitioned implicitly and can not be "
1959 "partitioned again explicitly."));
1960 Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
1961 Assert(cell_connection_graph.n_rows() == triangulation.n_active_cells(),
1962 ExcMessage("Connectivity graph has wrong size"));
1963 Assert(cell_connection_graph.n_cols() == triangulation.n_active_cells(),
1964 ExcMessage("Connectivity graph has wrong size"));
1965
1966 // signal that partitioning is going to happen
1967 triangulation.signals.pre_partition();
1968
1969 // check for an easy return
1970 if (n_partitions == 1)
1971 {
1972 for (const auto &cell : triangulation.active_cell_iterators())
1973 cell->set_subdomain_id(0);
1974 return;
1975 }
1976
1977 // partition this connection graph and get
1978 // back a vector of indices, one per degree
1979 // of freedom (which is associated with a
1980 // cell)
1981 std::vector<unsigned int> partition_indices(triangulation.n_active_cells());
1982 SparsityTools::partition(cell_connection_graph,
1983 cell_weights,
1984 n_partitions,
1985 partition_indices,
1986 partitioner);
1987
1988 // finally loop over all cells and set the subdomain ids
1989 for (const auto &cell : triangulation.active_cell_iterators())
1990 cell->set_subdomain_id(partition_indices[cell->active_cell_index()]);
1991 }
1992
1993
1994 namespace internal
1995 {
1999 template <class IT>
2000 void
2002 unsigned int &current_proc_idx,
2003 unsigned int &current_cell_idx,
2004 const unsigned int n_active_cells,
2005 const unsigned int n_partitions)
2006 {
2007 if (cell->is_active())
2008 {
2009 while (current_cell_idx >=
2010 std::floor(static_cast<std::uint_least64_t>(n_active_cells) *
2011 (current_proc_idx + 1) / n_partitions))
2012 ++current_proc_idx;
2013 cell->set_subdomain_id(current_proc_idx);
2014 ++current_cell_idx;
2015 }
2016 else
2017 {
2018 for (unsigned int n = 0; n < cell->n_children(); ++n)
2020 current_proc_idx,
2021 current_cell_idx,
2022 n_active_cells,
2023 n_partitions);
2024 }
2025 }
2026 } // namespace internal
2027
2028 template <int dim, int spacedim>
2029 void
2030 partition_triangulation_zorder(const unsigned int n_partitions,
2031 Triangulation<dim, spacedim> &triangulation,
2032 const bool group_siblings)
2033 {
2035 &triangulation) == nullptr),
2036 ExcMessage("Objects of type parallel::distributed::Triangulation "
2037 "are already partitioned implicitly and can not be "
2038 "partitioned again explicitly."));
2039 Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
2040 Assert(triangulation.signals.weight.empty(), ExcNotImplemented());
2041
2042 // signal that partitioning is going to happen
2043 triangulation.signals.pre_partition();
2044
2045 // check for an easy return
2046 if (n_partitions == 1)
2047 {
2048 for (const auto &cell : triangulation.active_cell_iterators())
2049 cell->set_subdomain_id(0);
2050 return;
2051 }
2052
2053 // Duplicate the coarse cell reordoring
2054 // as done in p4est
2055 std::vector<types::global_dof_index> coarse_cell_to_p4est_tree_permutation;
2056 std::vector<types::global_dof_index> p4est_tree_to_coarse_cell_permutation;
2057
2058 DynamicSparsityPattern cell_connectivity;
2060 0,
2061 cell_connectivity);
2062 coarse_cell_to_p4est_tree_permutation.resize(triangulation.n_cells(0));
2063 SparsityTools::reorder_hierarchical(cell_connectivity,
2064 coarse_cell_to_p4est_tree_permutation);
2065
2066 p4est_tree_to_coarse_cell_permutation =
2067 Utilities::invert_permutation(coarse_cell_to_p4est_tree_permutation);
2068
2069 unsigned int current_proc_idx = 0;
2070 unsigned int current_cell_idx = 0;
2071 const unsigned int n_active_cells = triangulation.n_active_cells();
2072
2073 // set subdomain id for active cell descendants
2074 // of each coarse cell in permuted order
2075 for (unsigned int idx = 0; idx < triangulation.n_cells(0); ++idx)
2076 {
2077 const unsigned int coarse_cell_idx =
2078 p4est_tree_to_coarse_cell_permutation[idx];
2080 &triangulation, 0, coarse_cell_idx);
2081
2083 current_proc_idx,
2084 current_cell_idx,
2085 n_active_cells,
2086 n_partitions);
2087 }
2088
2089 // if all children of a cell are active (e.g. we
2090 // have a cell that is refined once and no part
2091 // is refined further), p4est places all of them
2092 // on the same processor. The new owner will be
2093 // the processor with the largest number of children
2094 // (ties are broken by picking the lower rank).
2095 // Duplicate this logic here.
2096 if (group_siblings)
2097 {
2099 cell = triangulation.begin(),
2100 endc = triangulation.end();
2101 for (; cell != endc; ++cell)
2102 {
2103 if (cell->is_active())
2104 continue;
2105 bool all_children_active = true;
2106 std::map<unsigned int, unsigned int> map_cpu_n_cells;
2107 for (unsigned int n = 0; n < cell->n_children(); ++n)
2108 if (!cell->child(n)->is_active())
2109 {
2110 all_children_active = false;
2111 break;
2112 }
2113 else
2114 ++map_cpu_n_cells[cell->child(n)->subdomain_id()];
2115
2116 if (!all_children_active)
2117 continue;
2118
2119 unsigned int new_owner = cell->child(0)->subdomain_id();
2120 for (std::map<unsigned int, unsigned int>::iterator it =
2121 map_cpu_n_cells.begin();
2122 it != map_cpu_n_cells.end();
2123 ++it)
2124 if (it->second > map_cpu_n_cells[new_owner])
2125 new_owner = it->first;
2126
2127 for (unsigned int n = 0; n < cell->n_children(); ++n)
2128 cell->child(n)->set_subdomain_id(new_owner);
2129 }
2130 }
2131 }
2132
2133
2134 template <int dim, int spacedim>
2135 void
2137 {
2138 unsigned int n_levels = triangulation.n_levels();
2139 for (int lvl = n_levels - 1; lvl >= 0; --lvl)
2140 {
2141 for (const auto &cell : triangulation.cell_iterators_on_level(lvl))
2142 {
2143 if (cell->is_active())
2144 cell->set_level_subdomain_id(cell->subdomain_id());
2145 else
2146 {
2147 Assert(cell->child(0)->level_subdomain_id() !=
2150 cell->set_level_subdomain_id(
2151 cell->child(0)->level_subdomain_id());
2152 }
2153 }
2154 }
2155 }
2156
2157 namespace internal
2158 {
2159 namespace
2160 {
2161 // Split get_subdomain_association() for p::d::T since we want to compile
2162 // it in 1d but none of the p4est stuff is available in 1d.
2163 template <int dim, int spacedim>
2164 void
2167 &triangulation,
2168 const std::vector<CellId> &cell_ids,
2169 [[maybe_unused]] std::vector<types::subdomain_id> &subdomain_ids)
2170 {
2171#ifndef DEAL_II_WITH_P4EST
2172 (void)triangulation;
2173 (void)cell_ids;
2174 Assert(
2175 false,
2176 ExcMessage(
2177 "You are attempting to use a functionality that is only available "
2178 "if deal.II was configured to use p4est, but cmake did not find a "
2179 "valid p4est library."));
2180#else
2181 // for parallel distributed triangulations, we will ask the p4est oracle
2182 // about the global partitioning of active cells since this information
2183 // is stored on every process
2184 for (const auto &cell_id : cell_ids)
2185 {
2186 // find descendent from coarse quadrant
2187 typename ::internal::p4est::types<dim>::quadrant p4est_cell,
2189
2190 ::internal::p4est::init_coarse_quadrant<dim>(p4est_cell);
2191 for (const auto &child_index : cell_id.get_child_indices())
2192 {
2193 ::internal::p4est::init_quadrant_children<dim>(
2194 p4est_cell, p4est_children);
2195 p4est_cell =
2196 p4est_children[static_cast<unsigned int>(child_index)];
2197 }
2198
2199 // find owning process, i.e., the subdomain id
2200 const int owner =
2202 const_cast<typename ::internal::p4est::types<dim>::forest
2203 *>(triangulation.get_p4est()),
2204 cell_id.get_coarse_cell_id(),
2205 &p4est_cell,
2207 triangulation.get_mpi_communicator()));
2208
2209 Assert(owner >= 0, ExcMessage("p4est should know the owner."));
2210
2211 subdomain_ids.push_back(owner);
2212 }
2213#endif
2214 }
2215
2216
2217
2218 template <int spacedim>
2219 void
2222 const std::vector<CellId> &,
2223 std::vector<types::subdomain_id> &)
2224 {
2226 }
2227 } // anonymous namespace
2228 } // namespace internal
2229
2230
2231
2232 template <int dim, int spacedim>
2233 std::vector<types::subdomain_id>
2235 const std::vector<CellId> &cell_ids)
2236 {
2237 std::vector<types::subdomain_id> subdomain_ids;
2238 subdomain_ids.reserve(cell_ids.size());
2239
2240 if (dynamic_cast<
2242 &triangulation) != nullptr)
2243 {
2245 }
2247 *parallel_tria = dynamic_cast<
2249 &triangulation))
2250 {
2251 internal::get_subdomain_association(*parallel_tria,
2252 cell_ids,
2253 subdomain_ids);
2254 }
2255 else if (const parallel::shared::Triangulation<dim, spacedim> *shared_tria =
2257 *>(&triangulation))
2258 {
2259 // for parallel shared triangulations, we need to access true subdomain
2260 // ids which are also valid for artificial cells
2261 const std::vector<types::subdomain_id> &true_subdomain_ids_of_cells =
2262 shared_tria->get_true_subdomain_ids_of_cells();
2263
2264 for (const auto &cell_id : cell_ids)
2265 {
2266 const unsigned int active_cell_index =
2267 shared_tria->create_cell_iterator(cell_id)->active_cell_index();
2268 subdomain_ids.push_back(
2269 true_subdomain_ids_of_cells[active_cell_index]);
2270 }
2271 }
2272 else
2273 {
2274 // the most general type of triangulation is the serial one. here, all
2275 // subdomain information is directly available
2276 for (const auto &cell_id : cell_ids)
2277 {
2278 subdomain_ids.push_back(
2279 triangulation.create_cell_iterator(cell_id)->subdomain_id());
2280 }
2281 }
2282
2283 return subdomain_ids;
2284 }
2285
2286
2287
2288 template <int dim, int spacedim>
2289 void
2291 std::vector<types::subdomain_id> &subdomain)
2292 {
2293 Assert(subdomain.size() == triangulation.n_active_cells(),
2294 ExcDimensionMismatch(subdomain.size(),
2295 triangulation.n_active_cells()));
2296 for (const auto &cell : triangulation.active_cell_iterators())
2297 subdomain[cell->active_cell_index()] = cell->subdomain_id();
2298 }
2299
2300
2301
2302 template <int dim, int spacedim>
2303 unsigned int
2305 const Triangulation<dim, spacedim> &triangulation,
2306 const types::subdomain_id subdomain)
2307 {
2308 unsigned int count = 0;
2309 for (const auto &cell : triangulation.active_cell_iterators())
2310 if (cell->subdomain_id() == subdomain)
2311 ++count;
2312
2313 return count;
2314 }
2315
2316
2317
2318 template <int dim, int spacedim>
2319 std::vector<bool>
2321 {
2322 // start with all vertices
2323 std::vector<bool> locally_owned_vertices =
2324 triangulation.get_used_vertices();
2325
2326 // if the triangulation is distributed, eliminate those that
2327 // are owned by other processors -- either because the vertex is
2328 // on an artificial cell, or because it is on a ghost cell with
2329 // a smaller subdomain
2330 if (const auto *tr = dynamic_cast<
2332 &triangulation))
2333 for (const auto &cell : triangulation.active_cell_iterators())
2334 if (cell->is_artificial() ||
2335 (cell->is_ghost() &&
2336 (cell->subdomain_id() < tr->locally_owned_subdomain())))
2337 for (const unsigned int v : cell->vertex_indices())
2338 locally_owned_vertices[cell->vertex_index(v)] = false;
2339
2340 return locally_owned_vertices;
2341 }
2342
2343
2344
2345 namespace internal
2346 {
2347 namespace FixUpDistortedChildCells
2348 {
2349 // compute the mean square
2350 // deviation of the alternating
2351 // forms of the children of the
2352 // given object from that of
2353 // the object itself. for
2354 // objects with
2355 // structdim==spacedim, the
2356 // alternating form is the
2357 // determinant of the jacobian,
2358 // whereas for faces with
2359 // structdim==spacedim-1, the
2360 // alternating form is the
2361 // (signed and scaled) normal
2362 // vector
2363 //
2364 // this average square
2365 // deviation is computed for an
2366 // object where the center node
2367 // has been replaced by the
2368 // second argument to this
2369 // function
2370 template <typename Iterator, int spacedim>
2371 double
2372 objective_function(const Iterator &object,
2373 const Point<spacedim> &object_mid_point)
2374 {
2375 const unsigned int structdim =
2376 Iterator::AccessorType::structure_dimension;
2377 Assert(spacedim == Iterator::AccessorType::dimension,
2379
2380 // everything below is wrong
2381 // if not for the following
2382 // condition
2383 Assert(object->refinement_case() ==
2386 // first calculate the
2387 // average alternating form
2388 // for the parent cell/face
2391 Tensor<spacedim - structdim, spacedim>
2392 parent_alternating_forms[GeometryInfo<structdim>::vertices_per_cell];
2393
2394 for (const unsigned int i : object->vertex_indices())
2395 parent_vertices[i] = object->vertex(i);
2396
2398 parent_vertices, parent_alternating_forms);
2399
2400 const Tensor<spacedim - structdim, spacedim>
2401 average_parent_alternating_form =
2402 std::accumulate(parent_alternating_forms,
2403 parent_alternating_forms +
2406
2407 // now do the same
2408 // computation for the
2409 // children where we use the
2410 // given location for the
2411 // object mid point instead of
2412 // the one the triangulation
2413 // currently reports
2417 Tensor<spacedim - structdim, spacedim> child_alternating_forms
2420
2421 for (unsigned int c = 0; c < object->n_children(); ++c)
2422 for (const unsigned int i : object->child(c)->vertex_indices())
2423 child_vertices[c][i] = object->child(c)->vertex(i);
2424
2425 // replace mid-object
2426 // vertex. note that for
2427 // child i, the mid-object
2428 // vertex happens to have the
2429 // number
2430 // max_children_per_cell-i
2431 for (unsigned int c = 0; c < object->n_children(); ++c)
2433 1] = object_mid_point;
2434
2435 for (unsigned int c = 0; c < object->n_children(); ++c)
2437 child_vertices[c], child_alternating_forms[c]);
2438
2439 // on a uniformly refined
2440 // hypercube object, the child
2441 // alternating forms should
2442 // all be smaller by a factor
2443 // of 2^structdim than the
2444 // ones of the parent. as a
2445 // consequence, we'll use the
2446 // squared deviation from
2447 // this ideal value as an
2448 // objective function
2449 double objective = 0;
2450 for (unsigned int c = 0; c < object->n_children(); ++c)
2451 for (const unsigned int i : object->child(c)->vertex_indices())
2452 objective += (child_alternating_forms[c][i] -
2453 average_parent_alternating_form /
2454 Utilities::fixed_power<structdim>(2))
2455 .norm_square();
2456
2457 return objective;
2458 }
2459
2460
2466 template <typename Iterator>
2468 get_face_midpoint(const Iterator &object,
2469 const unsigned int f,
2470 std::integral_constant<int, 1>)
2471 {
2472 return object->vertex(f);
2473 }
2474
2475
2476
2482 template <typename Iterator>
2484 get_face_midpoint(const Iterator &object,
2485 const unsigned int f,
2486 std::integral_constant<int, 2>)
2487 {
2488 return object->line(f)->center();
2489 }
2490
2491
2492
2498 template <typename Iterator>
2500 get_face_midpoint(const Iterator &object,
2501 const unsigned int f,
2502 std::integral_constant<int, 3>)
2503 {
2504 return object->face(f)->center();
2505 }
2506
2507
2508
2531 template <typename Iterator>
2532 double
2533 minimal_diameter(const Iterator &object)
2534 {
2535 const unsigned int structdim =
2536 Iterator::AccessorType::structure_dimension;
2537
2538 double diameter = object->diameter();
2539 for (const unsigned int f : object->face_indices())
2540 for (unsigned int e = f + 1; e < object->n_faces(); ++e)
2542 diameter,
2543 get_face_midpoint(object,
2544 f,
2545 std::integral_constant<int, structdim>())
2546 .distance(get_face_midpoint(
2547 object, e, std::integral_constant<int, structdim>())));
2548
2549 return diameter;
2550 }
2551
2552
2553
2558 template <typename Iterator>
2559 bool
2560 fix_up_object(const Iterator &object)
2561 {
2562 const unsigned int structdim =
2563 Iterator::AccessorType::structure_dimension;
2564 const unsigned int spacedim = Iterator::AccessorType::space_dimension;
2565
2566 // right now we can only deal with cells that have been refined
2567 // isotropically because that is the only case where we have a cell
2568 // mid-point that can be moved around without having to consider
2569 // boundary information
2570 Assert(object->has_children(), ExcInternalError());
2571 Assert(object->refinement_case() ==
2574
2575 // get the current location of the object mid-vertex:
2576 Point<spacedim> object_mid_point = object->child(0)->vertex(
2578
2579 // now do a few steepest descent steps to reduce the objective
2580 // function. compute the diameter in the helper function above
2581 unsigned int iteration = 0;
2582 const double diameter = minimal_diameter(object);
2583
2584 // current value of objective function and initial delta
2585 double current_value = objective_function(object, object_mid_point);
2586 double initial_delta = 0;
2587
2588 do
2589 {
2590 // choose a step length that is initially 1/4 of the child
2591 // objects' diameter, and a sequence whose sum does not converge
2592 // (to avoid premature termination of the iteration)
2593 const double step_length = diameter / 4 / (iteration + 1);
2594
2595 // compute the objective function's derivative using a two-sided
2596 // difference formula with eps=step_length/10
2597 Tensor<1, spacedim> gradient;
2598 for (unsigned int d = 0; d < spacedim; ++d)
2599 {
2600 const double eps = step_length / 10;
2601
2603 h[d] = eps / 2;
2604
2605 gradient[d] =
2607 object, project_to_object(object, object_mid_point + h)) -
2609 object, project_to_object(object, object_mid_point - h))) /
2610 eps;
2611 }
2612
2613 // there is nowhere to go
2614 if (gradient.norm() == 0)
2615 break;
2616
2617 // We need to go in direction -gradient. the optimal value of the
2618 // objective function is zero, so assuming that the model is
2619 // quadratic we would have to go -2*val/||gradient|| in this
2620 // direction, make sure we go at most step_length into this
2621 // direction
2622 object_mid_point -=
2623 std::min(2 * current_value / (gradient * gradient),
2624 step_length / gradient.norm()) *
2625 gradient;
2626 object_mid_point = project_to_object(object, object_mid_point);
2627
2628 // compute current value of the objective function
2629 const double previous_value = current_value;
2630 current_value = objective_function(object, object_mid_point);
2631
2632 if (iteration == 0)
2633 initial_delta = (previous_value - current_value);
2634
2635 // stop if we aren't moving much any more
2636 if ((iteration >= 1) &&
2637 ((previous_value - current_value < 0) ||
2638 (std::fabs(previous_value - current_value) <
2639 0.001 * initial_delta)))
2640 break;
2641
2642 ++iteration;
2643 }
2644 while (iteration < 20);
2645
2646 // verify that the new
2647 // location is indeed better
2648 // than the one before. check
2649 // this by comparing whether
2650 // the minimum value of the
2651 // products of parent and
2652 // child alternating forms is
2653 // positive. for cells this
2654 // means that the
2655 // determinants have the same
2656 // sign, for faces that the
2657 // face normals of parent and
2658 // children point in the same
2659 // general direction
2660 double old_min_product, new_min_product;
2661
2664 for (const unsigned int i : GeometryInfo<structdim>::vertex_indices())
2665 parent_vertices[i] = object->vertex(i);
2666
2667 Tensor<spacedim - structdim, spacedim>
2668 parent_alternating_forms[GeometryInfo<structdim>::vertices_per_cell];
2670 parent_vertices, parent_alternating_forms);
2671
2675
2676 for (unsigned int c = 0; c < object->n_children(); ++c)
2677 for (const unsigned int i : object->child(c)->vertex_indices())
2678 child_vertices[c][i] = object->child(c)->vertex(i);
2679
2680 Tensor<spacedim - structdim, spacedim> child_alternating_forms
2683
2684 for (unsigned int c = 0; c < object->n_children(); ++c)
2686 child_vertices[c], child_alternating_forms[c]);
2687
2688 old_min_product =
2689 child_alternating_forms[0][0] * parent_alternating_forms[0];
2690 for (unsigned int c = 0; c < object->n_children(); ++c)
2691 for (const unsigned int i : object->child(c)->vertex_indices())
2692 for (const unsigned int j : object->vertex_indices())
2693 old_min_product = std::min<double>(old_min_product,
2694 child_alternating_forms[c][i] *
2695 parent_alternating_forms[j]);
2696
2697 // for the new minimum value,
2698 // replace mid-object
2699 // vertex. note that for child
2700 // i, the mid-object vertex
2701 // happens to have the number
2702 // max_children_per_cell-i
2703 for (unsigned int c = 0; c < object->n_children(); ++c)
2705 1] = object_mid_point;
2706
2707 for (unsigned int c = 0; c < object->n_children(); ++c)
2709 child_vertices[c], child_alternating_forms[c]);
2710
2711 new_min_product =
2712 child_alternating_forms[0][0] * parent_alternating_forms[0];
2713 for (unsigned int c = 0; c < object->n_children(); ++c)
2714 for (const unsigned int i : object->child(c)->vertex_indices())
2715 for (const unsigned int j : object->vertex_indices())
2716 new_min_product = std::min<double>(new_min_product,
2717 child_alternating_forms[c][i] *
2718 parent_alternating_forms[j]);
2719
2720 // if new minimum value is
2721 // better than before, then set the
2722 // new mid point. otherwise
2723 // return this object as one of
2724 // those that can't apparently
2725 // be fixed
2726 if (new_min_product >= old_min_product)
2727 object->child(0)->vertex(
2729 object_mid_point;
2730
2731 // return whether after this
2732 // operation we have an object that
2733 // is well oriented
2734 return (std::max(new_min_product, old_min_product) > 0);
2735 }
2736
2737
2738
2739 // possibly fix up the faces of a cell by moving around its mid-points
2740 template <int dim, int spacedim>
2741 void
2743 const typename ::Triangulation<dim, spacedim>::cell_iterator
2744 &cell,
2745 std::integral_constant<int, dim>,
2746 std::integral_constant<int, spacedim>)
2747 {
2748 // see if we first can fix up some of the faces of this object. We can
2749 // mess with faces if and only if the neighboring cell is not even
2750 // more refined than we are (since in that case the sub-faces have
2751 // themselves children that we can't move around any more). however,
2752 // the latter case shouldn't happen anyway: if the current face is
2753 // distorted but the neighbor is even more refined, then the face had
2754 // been deformed before already, and had been ignored at the time; we
2755 // should then also be able to ignore it this time as well
2756 for (auto f : cell->face_indices())
2757 {
2758 Assert(cell->face(f)->has_children(), ExcInternalError());
2759 Assert(cell->face(f)->refinement_case() ==
2762
2763 bool subface_is_more_refined = false;
2764 for (unsigned int g = 0;
2765 g < GeometryInfo<dim>::max_children_per_face;
2766 ++g)
2767 if (cell->face(f)->child(g)->has_children())
2768 {
2769 subface_is_more_refined = true;
2770 break;
2771 }
2772
2773 if (subface_is_more_refined == true)
2774 continue;
2775
2776 // we finally know that we can do something about this face
2777 fix_up_object(cell->face(f));
2778 }
2779 }
2780 } /* namespace FixUpDistortedChildCells */
2781 } /* namespace internal */
2782
2783
2784 template <int dim, int spacedim>
2785 void
2787 const bool reset_boundary_ids)
2788 {
2789 const auto src_boundary_ids = tria.get_boundary_ids();
2790 std::vector<types::manifold_id> dst_manifold_ids(src_boundary_ids.size());
2791 auto m_it = dst_manifold_ids.begin();
2792 for (const auto b : src_boundary_ids)
2793 {
2794 *m_it = static_cast<types::manifold_id>(b);
2795 ++m_it;
2796 }
2797 const std::vector<types::boundary_id> reset_boundary_id =
2798 reset_boundary_ids ?
2799 std::vector<types::boundary_id>(src_boundary_ids.size(), 0) :
2800 src_boundary_ids;
2801 map_boundary_to_manifold_ids(src_boundary_ids,
2802 dst_manifold_ids,
2803 tria,
2804 reset_boundary_id);
2805 }
2806
2807
2808
2809 template <int dim, int spacedim>
2810 void
2812 const std::vector<types::boundary_id> &src_boundary_ids,
2813 const std::vector<types::manifold_id> &dst_manifold_ids,
2815 const std::vector<types::boundary_id> &reset_boundary_ids_)
2816 {
2817 AssertDimension(src_boundary_ids.size(), dst_manifold_ids.size());
2818 const auto reset_boundary_ids =
2819 reset_boundary_ids_.size() ? reset_boundary_ids_ : src_boundary_ids;
2820 AssertDimension(reset_boundary_ids.size(), src_boundary_ids.size());
2821
2822 // in 3d, we not only have to copy boundary ids of faces, but also of edges
2823 // because we see them twice (once from each adjacent boundary face),
2824 // we cannot immediately reset their boundary ids. thus, copy first
2825 // and reset later
2826 if (dim >= 3)
2827 for (const auto &cell : tria.active_cell_iterators())
2828 for (auto f : cell->face_indices())
2829 if (cell->face(f)->at_boundary())
2830 for (unsigned int e = 0; e < cell->face(f)->n_lines(); ++e)
2831 {
2832 const auto bid = cell->face(f)->line(e)->boundary_id();
2833 const unsigned int ind = std::find(src_boundary_ids.begin(),
2834 src_boundary_ids.end(),
2835 bid) -
2836 src_boundary_ids.begin();
2837 if (ind < src_boundary_ids.size())
2838 cell->face(f)->line(e)->set_manifold_id(
2839 dst_manifold_ids[ind]);
2840 }
2841
2842 // now do cells
2843 for (const auto &cell : tria.active_cell_iterators())
2844 for (auto f : cell->face_indices())
2845 if (cell->face(f)->at_boundary())
2846 {
2847 const auto bid = cell->face(f)->boundary_id();
2848 const unsigned int ind =
2849 std::find(src_boundary_ids.begin(), src_boundary_ids.end(), bid) -
2850 src_boundary_ids.begin();
2851
2852 if (ind < src_boundary_ids.size())
2853 {
2854 // assign the manifold id
2855 cell->face(f)->set_manifold_id(dst_manifold_ids[ind]);
2856 // then reset boundary id
2857 cell->face(f)->set_boundary_id(reset_boundary_ids[ind]);
2858 }
2859
2860 if (dim >= 3)
2861 for (unsigned int e = 0; e < cell->face(f)->n_lines(); ++e)
2862 {
2863 const auto bid = cell->face(f)->line(e)->boundary_id();
2864 const unsigned int ind = std::find(src_boundary_ids.begin(),
2865 src_boundary_ids.end(),
2866 bid) -
2867 src_boundary_ids.begin();
2868 if (ind < src_boundary_ids.size())
2869 cell->face(f)->line(e)->set_boundary_id(
2870 reset_boundary_ids[ind]);
2871 }
2872 }
2873 }
2874
2875
2876 template <int dim, int spacedim>
2877 void
2879 const bool compute_face_ids)
2880 {
2882 cell = tria.begin_active(),
2883 endc = tria.end();
2884
2885 for (; cell != endc; ++cell)
2886 {
2887 cell->set_manifold_id(cell->material_id());
2888 if (compute_face_ids == true)
2889 {
2890 for (auto f : cell->face_indices())
2891 {
2892 if (cell->at_boundary(f) == false)
2893 cell->face(f)->set_manifold_id(
2894 std::min(cell->material_id(),
2895 cell->neighbor(f)->material_id()));
2896 else
2897 cell->face(f)->set_manifold_id(cell->material_id());
2898 }
2899 }
2900 }
2901 }
2902
2903
2904 template <int dim, int spacedim>
2905 void
2908 const std::function<types::manifold_id(
2909 const std::set<types::manifold_id> &)> &disambiguation_function,
2910 bool overwrite_only_flat_manifold_ids)
2911 {
2912 // Easy case first:
2913 if (dim == 1)
2914 return;
2915 const unsigned int n_subobjects =
2916 dim == 2 ? tria.n_lines() : tria.n_lines() + tria.n_quads();
2917
2918 // If user index is zero, then it has not been set.
2919 std::vector<std::set<types::manifold_id>> manifold_ids(n_subobjects + 1);
2920 std::vector<unsigned int> backup;
2921 tria.save_user_indices(backup);
2922 tria.clear_user_data();
2923
2924 unsigned next_index = 1;
2925 for (auto &cell : tria.active_cell_iterators())
2926 {
2927 if (dim > 1)
2928 for (unsigned int l = 0; l < cell->n_lines(); ++l)
2929 {
2930 if (cell->line(l)->user_index() == 0)
2931 {
2932 AssertIndexRange(next_index, n_subobjects + 1);
2933 manifold_ids[next_index].insert(cell->manifold_id());
2934 cell->line(l)->set_user_index(next_index++);
2935 }
2936 else
2937 manifold_ids[cell->line(l)->user_index()].insert(
2938 cell->manifold_id());
2939 }
2940 if (dim > 2)
2941 for (unsigned int l = 0; l < cell->n_faces(); ++l)
2942 {
2943 if (cell->quad(l)->user_index() == 0)
2944 {
2945 AssertIndexRange(next_index, n_subobjects + 1);
2946 manifold_ids[next_index].insert(cell->manifold_id());
2947 cell->quad(l)->set_user_index(next_index++);
2948 }
2949 else
2950 manifold_ids[cell->quad(l)->user_index()].insert(
2951 cell->manifold_id());
2952 }
2953 }
2954 for (auto &cell : tria.active_cell_iterators())
2955 {
2956 if (dim > 1)
2957 for (unsigned int l = 0; l < cell->n_lines(); ++l)
2958 {
2959 const auto id = cell->line(l)->user_index();
2960 // Make sure we change the manifold indicator only once
2961 if (id != 0)
2962 {
2963 if (cell->line(l)->manifold_id() ==
2965 overwrite_only_flat_manifold_ids == false)
2966 cell->line(l)->set_manifold_id(
2967 disambiguation_function(manifold_ids[id]));
2968 cell->line(l)->set_user_index(0);
2969 }
2970 }
2971 if (dim > 2)
2972 for (unsigned int l = 0; l < cell->n_faces(); ++l)
2973 {
2974 const auto id = cell->quad(l)->user_index();
2975 // Make sure we change the manifold indicator only once
2976 if (id != 0)
2977 {
2978 if (cell->quad(l)->manifold_id() ==
2980 overwrite_only_flat_manifold_ids == false)
2981 cell->quad(l)->set_manifold_id(
2982 disambiguation_function(manifold_ids[id]));
2983 cell->quad(l)->set_user_index(0);
2984 }
2985 }
2986 }
2987 tria.load_user_indices(backup);
2988 }
2989
2990
2991
2992 template <int dim, int spacedim>
2993 void
2995 const double limit_angle_fraction)
2996 {
2997 if (dim == 1)
2998 return; // Nothing to do
2999
3000 // Check that we don't have hanging nodes
3002 ExcMessage("The input Triangulation cannot "
3003 "have hanging nodes."));
3004
3006
3007 bool has_cells_with_more_than_dim_faces_on_boundary = true;
3008 bool has_cells_with_dim_faces_on_boundary = false;
3009
3010 unsigned int refinement_cycles = 0;
3011
3012 while (has_cells_with_more_than_dim_faces_on_boundary)
3013 {
3014 has_cells_with_more_than_dim_faces_on_boundary = false;
3015
3016 for (const auto &cell : tria.active_cell_iterators())
3017 {
3018 unsigned int boundary_face_counter = 0;
3019 for (auto f : cell->face_indices())
3020 if (cell->face(f)->at_boundary())
3021 ++boundary_face_counter;
3022 if (boundary_face_counter > dim)
3023 {
3024 has_cells_with_more_than_dim_faces_on_boundary = true;
3025 break;
3026 }
3027 else if (boundary_face_counter == dim)
3028 has_cells_with_dim_faces_on_boundary = true;
3029 }
3030 if (has_cells_with_more_than_dim_faces_on_boundary)
3031 {
3032 tria.refine_global(1);
3033 ++refinement_cycles;
3034 }
3035 }
3036
3037 if (has_cells_with_dim_faces_on_boundary)
3038 {
3039 tria.refine_global(1);
3040 ++refinement_cycles;
3041 }
3042 else
3043 {
3044 while (refinement_cycles > 0)
3045 {
3046 for (const auto &cell : tria.active_cell_iterators())
3047 cell->set_coarsen_flag();
3049 refinement_cycles--;
3050 }
3051 return;
3052 }
3053
3054 std::vector<bool> cells_to_remove(tria.n_active_cells(), false);
3055 std::vector<Point<spacedim>> vertices = tria.get_vertices();
3056
3057 std::vector<bool> faces_to_remove(tria.n_raw_faces(), false);
3058
3059 std::vector<CellData<dim>> cells_to_add;
3060 SubCellData subcelldata_to_add;
3061
3062 // Trick compiler for dimension independent things
3063 const unsigned int v0 = 0, v1 = 1, v2 = (dim > 1 ? 2 : 0),
3064 v3 = (dim > 1 ? 3 : 0);
3065
3066 for (const auto &cell : tria.active_cell_iterators())
3067 {
3068 double angle_fraction = 0;
3069 unsigned int vertex_at_corner = numbers::invalid_unsigned_int;
3070
3071 if (dim == 2)
3072 {
3074 p0[spacedim > 1 ? 1 : 0] = 1;
3076 p1[0] = 1;
3077
3078 if (cell->face(v0)->at_boundary() && cell->face(v3)->at_boundary())
3079 {
3080 p0 = cell->vertex(v0) - cell->vertex(v2);
3081 p1 = cell->vertex(v3) - cell->vertex(v2);
3082 vertex_at_corner = v2;
3083 }
3084 else if (cell->face(v3)->at_boundary() &&
3085 cell->face(v1)->at_boundary())
3086 {
3087 p0 = cell->vertex(v2) - cell->vertex(v3);
3088 p1 = cell->vertex(v1) - cell->vertex(v3);
3089 vertex_at_corner = v3;
3090 }
3091 else if (cell->face(1)->at_boundary() &&
3092 cell->face(2)->at_boundary())
3093 {
3094 p0 = cell->vertex(v0) - cell->vertex(v1);
3095 p1 = cell->vertex(v3) - cell->vertex(v1);
3096 vertex_at_corner = v1;
3097 }
3098 else if (cell->face(2)->at_boundary() &&
3099 cell->face(0)->at_boundary())
3100 {
3101 p0 = cell->vertex(v2) - cell->vertex(v0);
3102 p1 = cell->vertex(v1) - cell->vertex(v0);
3103 vertex_at_corner = v0;
3104 }
3105 p0 /= p0.norm();
3106 p1 /= p1.norm();
3107 angle_fraction = std::acos(p0 * p1) / numbers::PI;
3108 }
3109 else
3110 {
3112 }
3113
3114 if (angle_fraction > limit_angle_fraction)
3115 {
3116 auto flags_removal = [&](unsigned int f1,
3117 unsigned int f2,
3118 unsigned int n1,
3119 unsigned int n2) -> void {
3120 cells_to_remove[cell->active_cell_index()] = true;
3121 cells_to_remove[cell->neighbor(n1)->active_cell_index()] = true;
3122 cells_to_remove[cell->neighbor(n2)->active_cell_index()] = true;
3123
3124 faces_to_remove[cell->face(f1)->index()] = true;
3125 faces_to_remove[cell->face(f2)->index()] = true;
3126
3127 faces_to_remove[cell->neighbor(n1)->face(f1)->index()] = true;
3128 faces_to_remove[cell->neighbor(n2)->face(f2)->index()] = true;
3129 };
3130
3131 auto cell_creation = [&](const unsigned int vv0,
3132 const unsigned int vv1,
3133 const unsigned int f0,
3134 const unsigned int f1,
3135
3136 const unsigned int n0,
3137 const unsigned int v0n0,
3138 const unsigned int v1n0,
3139
3140 const unsigned int n1,
3141 const unsigned int v0n1,
3142 const unsigned int v1n1) {
3143 CellData<dim> c1, c2;
3144 CellData<1> l1, l2;
3145
3146 c1.vertices[v0] = cell->vertex_index(vv0);
3147 c1.vertices[v1] = cell->vertex_index(vv1);
3148 c1.vertices[v2] = cell->neighbor(n0)->vertex_index(v0n0);
3149 c1.vertices[v3] = cell->neighbor(n0)->vertex_index(v1n0);
3150
3151 c1.manifold_id = cell->manifold_id();
3152 c1.material_id = cell->material_id();
3153
3154 c2.vertices[v0] = cell->vertex_index(vv0);
3155 c2.vertices[v1] = cell->neighbor(n1)->vertex_index(v0n1);
3156 c2.vertices[v2] = cell->vertex_index(vv1);
3157 c2.vertices[v3] = cell->neighbor(n1)->vertex_index(v1n1);
3158
3159 c2.manifold_id = cell->manifold_id();
3160 c2.material_id = cell->material_id();
3161
3162 l1.vertices[0] = cell->vertex_index(vv0);
3163 l1.vertices[1] = cell->neighbor(n0)->vertex_index(v0n0);
3164
3165 l1.boundary_id = cell->line(f0)->boundary_id();
3166 l1.manifold_id = cell->line(f0)->manifold_id();
3167 subcelldata_to_add.boundary_lines.push_back(l1);
3168
3169 l2.vertices[0] = cell->vertex_index(vv0);
3170 l2.vertices[1] = cell->neighbor(n1)->vertex_index(v0n1);
3171
3172 l2.boundary_id = cell->line(f1)->boundary_id();
3173 l2.manifold_id = cell->line(f1)->manifold_id();
3174 subcelldata_to_add.boundary_lines.push_back(l2);
3175
3176 cells_to_add.push_back(c1);
3177 cells_to_add.push_back(c2);
3178 };
3179
3180 if (dim == 2)
3181 {
3182 switch (vertex_at_corner)
3183 {
3184 case 0:
3185 flags_removal(0, 2, 3, 1);
3186 cell_creation(0, 3, 0, 2, 3, 2, 3, 1, 1, 3);
3187 break;
3188 case 1:
3189 flags_removal(1, 2, 3, 0);
3190 cell_creation(1, 2, 2, 1, 0, 0, 2, 3, 3, 2);
3191 break;
3192 case 2:
3193 flags_removal(3, 0, 1, 2);
3194 cell_creation(2, 1, 3, 0, 1, 3, 1, 2, 0, 1);
3195 break;
3196 case 3:
3197 flags_removal(3, 1, 0, 2);
3198 cell_creation(3, 0, 1, 3, 2, 1, 0, 0, 2, 0);
3199 break;
3200 }
3201 }
3202 else
3203 {
3205 }
3206 }
3207 }
3208
3209 // if no cells need to be added, then no regularization is necessary.
3210 // Restore things as they were before this function was called.
3211 if (cells_to_add.empty())
3212 {
3213 while (refinement_cycles > 0)
3214 {
3215 for (const auto &cell : tria.active_cell_iterators())
3216 cell->set_coarsen_flag();
3218 refinement_cycles--;
3219 }
3220 return;
3221 }
3222
3223 // add the cells that were not marked as skipped
3224 for (const auto &cell : tria.active_cell_iterators())
3225 {
3226 if (cells_to_remove[cell->active_cell_index()] == false)
3227 {
3228 CellData<dim> c(cell->n_vertices());
3229 for (const unsigned int v : cell->vertex_indices())
3230 c.vertices[v] = cell->vertex_index(v);
3231 c.manifold_id = cell->manifold_id();
3232 c.material_id = cell->material_id();
3233 cells_to_add.push_back(c);
3234 }
3235 }
3236
3237 // Face counter for both dim == 2 and dim == 3
3239 face = tria.begin_active_face(),
3240 endf = tria.end_face();
3241 for (; face != endf; ++face)
3242 if ((face->at_boundary() ||
3243 face->manifold_id() != numbers::flat_manifold_id) &&
3244 faces_to_remove[face->index()] == false)
3245 {
3246 for (unsigned int l = 0; l < face->n_lines(); ++l)
3247 {
3248 CellData<1> line;
3249 if (dim == 2)
3250 {
3251 for (const unsigned int v : face->vertex_indices())
3252 line.vertices[v] = face->vertex_index(v);
3253 line.boundary_id = face->boundary_id();
3254 line.manifold_id = face->manifold_id();
3255 }
3256 else
3257 {
3258 for (const unsigned int v : face->line(l)->vertex_indices())
3259 line.vertices[v] = face->line(l)->vertex_index(v);
3260 line.boundary_id = face->line(l)->boundary_id();
3261 line.manifold_id = face->line(l)->manifold_id();
3262 }
3263 subcelldata_to_add.boundary_lines.push_back(line);
3264 }
3265 if (dim == 3)
3266 {
3267 CellData<2> quad(face->n_vertices());
3268 for (const unsigned int v : face->vertex_indices())
3269 quad.vertices[v] = face->vertex_index(v);
3270 quad.boundary_id = face->boundary_id();
3271 quad.manifold_id = face->manifold_id();
3272 subcelldata_to_add.boundary_quads.push_back(quad);
3273 }
3274 }
3276 cells_to_add,
3277 subcelldata_to_add);
3279
3280 // Save manifolds
3281 auto manifold_ids = tria.get_manifold_ids();
3282 std::map<types::manifold_id, std::unique_ptr<Manifold<dim, spacedim>>>
3283 manifolds;
3284 // Set manifolds in new Triangulation
3285 for (const auto manifold_id : manifold_ids)
3286 if (manifold_id != numbers::flat_manifold_id)
3287 manifolds[manifold_id] = tria.get_manifold(manifold_id).clone();
3288
3289 tria.clear();
3290
3291 tria.create_triangulation(vertices, cells_to_add, subcelldata_to_add);
3292
3293 // Restore manifolds
3294 for (const auto manifold_id : manifold_ids)
3295 if (manifold_id != numbers::flat_manifold_id)
3296 tria.set_manifold(manifold_id, *manifolds[manifold_id]);
3297 }
3298
3299
3300
3301 template <int dim, int spacedim>
3302#ifndef DOXYGEN
3303 std::tuple<
3304 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
3305 std::vector<std::vector<Point<dim>>>,
3306 std::vector<std::vector<unsigned int>>>
3307#else
3308 return_type
3309#endif
3311 const Cache<dim, spacedim> &cache,
3312 const std::vector<Point<spacedim>> &points,
3314 &cell_hint)
3315 {
3316 const auto cqmp = compute_point_locations_try_all(cache, points, cell_hint);
3317 // Splitting the tuple's components
3318 auto &cells = std::get<0>(cqmp);
3319 auto &qpoints = std::get<1>(cqmp);
3320 auto &maps = std::get<2>(cqmp);
3321
3322 return std::make_tuple(std::move(cells),
3323 std::move(qpoints),
3324 std::move(maps));
3325 }
3326
3327
3328
3329 template <int dim, int spacedim>
3330#ifndef DOXYGEN
3331 std::tuple<
3332 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
3333 std::vector<std::vector<Point<dim>>>,
3334 std::vector<std::vector<unsigned int>>,
3335 std::vector<unsigned int>>
3336#else
3337 return_type
3338#endif
3340 const Cache<dim, spacedim> &cache,
3341 const std::vector<Point<spacedim>> &points,
3343 &cell_hint)
3344 {
3345 Assert((dim == spacedim),
3346 ExcMessage("Only implemented for dim==spacedim."));
3347
3348 // Alias
3349 namespace bgi = boost::geometry::index;
3350
3351 // Get the mapping
3352 const auto &mapping = cache.get_mapping();
3353
3354 // How many points are here?
3355 const unsigned int np = points.size();
3356
3357 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
3358 cells_out;
3359 std::vector<std::vector<Point<dim>>> qpoints_out;
3360 std::vector<std::vector<unsigned int>> maps_out;
3361 std::vector<unsigned int> missing_points_out;
3362
3363 // Now the easy case.
3364 if (np == 0)
3365 return std::make_tuple(std::move(cells_out),
3366 std::move(qpoints_out),
3367 std::move(maps_out),
3368 std::move(missing_points_out));
3369
3370 // For the search we shall use the following tree
3371 const auto &b_tree = cache.get_cell_bounding_boxes_rtree();
3372
3373 // Now make a tree of indices for the points
3374 // [TODO] This would work better with pack_rtree_of_indices, but
3375 // windows does not like it. Build a tree with pairs of point and id
3376 std::vector<std::pair<Point<spacedim>, unsigned int>> points_and_ids(np);
3377 for (unsigned int i = 0; i < np; ++i)
3378 points_and_ids[i] = std::make_pair(points[i], i);
3379 const auto p_tree = pack_rtree(points_and_ids);
3380
3381 // Keep track of all found points
3382 std::vector<bool> found_points(points.size(), false);
3383
3384 // Check if a point was found
3385 const auto already_found = [&found_points](const auto &id) {
3386 AssertIndexRange(id.second, found_points.size());
3387 return found_points[id.second];
3388 };
3389
3390 // check if the given cell was already in the vector of cells before. If so,
3391 // insert in the corresponding vectors the reference point and the id.
3392 // Otherwise append a new entry to all vectors.
3393 const auto store_cell_point_and_id =
3394 [&](
3396 const Point<dim> &ref_point,
3397 const unsigned int &id) {
3398 const auto it = std::find(cells_out.rbegin(), cells_out.rend(), cell);
3399 if (it != cells_out.rend())
3400 {
3401 const auto cell_id =
3402 (cells_out.size() - 1 - (it - cells_out.rbegin()));
3403 qpoints_out[cell_id].emplace_back(ref_point);
3404 maps_out[cell_id].emplace_back(id);
3405 }
3406 else
3407 {
3408 cells_out.emplace_back(cell);
3409 qpoints_out.emplace_back(std::vector<Point<dim>>({ref_point}));
3410 maps_out.emplace_back(std::vector<unsigned int>({id}));
3411 }
3412 };
3413
3414 // Check all points within a given pair of box and cell
3415 const auto check_all_points_within_box = [&](const auto &leaf) {
3416 const double relative_tolerance = 1e-12;
3417 const BoundingBox<spacedim> box =
3418 leaf.first.create_extended_relative(relative_tolerance);
3419 const auto &cell_hint = leaf.second;
3420
3421 for (const auto &point_and_id :
3422 p_tree | bgi::adaptors::queried(!bgi::satisfies(already_found) &&
3423 bgi::intersects(box)))
3424 {
3425 const auto id = point_and_id.second;
3426 const auto cell_and_ref =
3428 points[id],
3429 cell_hint);
3430 const auto &cell = cell_and_ref.first;
3431 const auto &ref_point = cell_and_ref.second;
3432
3433 if (cell.state() == IteratorState::valid)
3434 store_cell_point_and_id(cell, ref_point, id);
3435 else
3436 missing_points_out.emplace_back(id);
3437
3438 // Don't look anymore for this point
3439 found_points[id] = true;
3440 }
3441 };
3442
3443 // If a hint cell was given, use it
3444 if (cell_hint.state() == IteratorState::valid)
3445 check_all_points_within_box(
3446 std::make_pair(mapping.get_bounding_box(cell_hint), cell_hint));
3447
3448 // Now loop over all points that have not been found yet
3449 for (unsigned int i = 0; i < np; ++i)
3450 if (found_points[i] == false)
3451 {
3452 // Get the closest cell to this point
3453 const auto leaf = b_tree.qbegin(bgi::nearest(points[i], 1));
3454 // Now checks all points that fall within this box
3455 if (leaf != b_tree.qend())
3456 check_all_points_within_box(*leaf);
3457 else
3458 {
3459 // We should not get here. Throw an error.
3461 }
3462 }
3463 // Now make sure we send out the rest of the points that we did not find.
3464 for (unsigned int i = 0; i < np; ++i)
3465 if (found_points[i] == false)
3466 missing_points_out.emplace_back(i);
3467
3468 // Debug Checking
3469 AssertDimension(cells_out.size(), maps_out.size());
3470 AssertDimension(cells_out.size(), qpoints_out.size());
3471
3472 if constexpr (running_in_debug_mode())
3473 {
3474 unsigned int c = cells_out.size();
3475 unsigned int qps = 0;
3476 // The number of points in all
3477 // the cells must be the same as
3478 // the number of points we
3479 // started off from,
3480 // plus the points which were ignored
3481 for (unsigned int n = 0; n < c; ++n)
3482 {
3483 AssertDimension(qpoints_out[n].size(), maps_out[n].size());
3484 qps += qpoints_out[n].size();
3485 }
3486
3487 Assert(qps + missing_points_out.size() == np,
3488 ExcDimensionMismatch(qps + missing_points_out.size(), np));
3489 }
3490
3491 return std::make_tuple(std::move(cells_out),
3492 std::move(qpoints_out),
3493 std::move(maps_out),
3494 std::move(missing_points_out));
3495 }
3496
3497
3498
3499 template <int dim, int spacedim>
3500#ifndef DOXYGEN
3501 std::tuple<
3502 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
3503 std::vector<std::vector<Point<dim>>>,
3504 std::vector<std::vector<unsigned int>>,
3505 std::vector<std::vector<Point<spacedim>>>,
3506 std::vector<std::vector<unsigned int>>>
3507#else
3508 return_type
3509#endif
3512 const std::vector<Point<spacedim>> &points,
3513 const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
3514 const double tolerance,
3515 const std::vector<bool> &marked_vertices,
3516 const bool enforce_unique_mapping)
3517 {
3518 // run internal function ...
3519 const auto all =
3521 points,
3522 global_bboxes,
3523 marked_vertices,
3524 tolerance,
3525 false,
3526 enforce_unique_mapping)
3527 .send_components;
3528
3529 // ... and reshuffle the data
3530 std::tuple<
3531 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
3532 std::vector<std::vector<Point<dim>>>,
3533 std::vector<std::vector<unsigned int>>,
3534 std::vector<std::vector<Point<spacedim>>>,
3535 std::vector<std::vector<unsigned int>>>
3536 result;
3537
3538 std::pair<int, int> dummy{-1, -1};
3539
3540 for (unsigned int i = 0; i < all.size(); ++i)
3541 {
3542 if (dummy != std::get<0>(all[i]))
3543 {
3544 std::get<0>(result).push_back(
3546 &cache.get_triangulation(),
3547 std::get<0>(all[i]).first,
3548 std::get<0>(all[i]).second});
3549
3550 const unsigned int new_size = std::get<0>(result).size();
3551
3552 std::get<1>(result).resize(new_size);
3553 std::get<2>(result).resize(new_size);
3554 std::get<3>(result).resize(new_size);
3555 std::get<4>(result).resize(new_size);
3556
3557 dummy = std::get<0>(all[i]);
3558 }
3559
3560 std::get<1>(result).back().push_back(
3561 std::get<3>(all[i])); // reference point
3562 std::get<2>(result).back().push_back(std::get<2>(all[i])); // index
3563 std::get<3>(result).back().push_back(std::get<4>(all[i])); // real point
3564 std::get<4>(result).back().push_back(std::get<1>(all[i])); // rank
3565 }
3566
3567 return result;
3568 }
3569
3570
3571
3572 namespace internal
3573 {
3580 template <int spacedim, typename T>
3581 std::tuple<std::vector<unsigned int>,
3582 std::vector<unsigned int>,
3583 std::vector<unsigned int>>
3585 const MPI_Comm comm,
3586 const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
3587 const std::vector<T> &entities,
3588 const double tolerance)
3589 {
3590 std::vector<std::pair<unsigned int, unsigned int>> ranks_and_indices;
3591 ranks_and_indices.reserve(entities.size());
3592
3593#if defined(DEAL_II_WITH_ARBORX)
3594 static constexpr bool use_arborx = true;
3595#else
3596 static constexpr bool use_arborx = false;
3597#endif
3598 // Lambda to process bboxes if global_bboxes.size()>1 or ArborX not
3599 // available
3600 const auto process_bboxes = [&]() -> void {
3601 std::vector<std::vector<BoundingBox<spacedim>>> global_bboxes_temp;
3602 auto *global_bboxes_to_be_used = &global_bboxes;
3603
3604 if (global_bboxes.size() == 1 && use_arborx == false)
3605 {
3606 global_bboxes_temp =
3607 Utilities::MPI::all_gather(comm, global_bboxes[0]);
3608 global_bboxes_to_be_used = &global_bboxes_temp;
3609 }
3610
3611 // helper function to determine if a bounding box is valid
3612 const auto is_valid = [](const auto &bb) {
3613 for (unsigned int i = 0; i < spacedim; ++i)
3614 if (bb.get_boundary_points().first[i] >
3615 bb.get_boundary_points().second[i])
3616 return false;
3617
3618 return true;
3619 };
3620
3621 // linearize vector of vectors
3622 std::vector<std::pair<BoundingBox<spacedim>, unsigned int>>
3623 boxes_and_ranks;
3624
3625 for (unsigned rank = 0; rank < global_bboxes_to_be_used->size(); ++rank)
3626 for (const auto &box : (*global_bboxes_to_be_used)[rank])
3627 if (is_valid(box))
3628 boxes_and_ranks.emplace_back(box, rank);
3629
3630 // pack boxes into r-tree
3631 const auto tree = pack_rtree(boxes_and_ranks);
3632
3633 // loop over all entities
3634 for (unsigned int i = 0; i < entities.size(); ++i)
3635 {
3636 // create a bounding box with tolerance
3637 const auto bb =
3638 BoundingBox<spacedim>(entities[i]).create_extended(tolerance);
3639
3640 // determine ranks potentially owning point/bounding box
3641 std::set<unsigned int> my_ranks;
3642
3643 for (const auto &box_and_rank :
3644 tree | boost::geometry::index::adaptors::queried(
3645 boost::geometry::index::intersects(bb)))
3646 my_ranks.insert(box_and_rank.second);
3647
3648 for (const auto rank : my_ranks)
3649 ranks_and_indices.emplace_back(rank, i);
3650 }
3651 };
3652
3653 if constexpr (use_arborx)
3654 {
3655 if (global_bboxes.size() == 1)
3656 {
3657 ArborXWrappers::DistributedTree distributed_tree(
3658 comm, global_bboxes[0]);
3659 std::vector<BoundingBox<spacedim>> query_bounding_boxes;
3660 query_bounding_boxes.reserve(entities.size());
3661 for (const auto &entity : entities)
3662 query_bounding_boxes.emplace_back(
3663 BoundingBox<spacedim>(entity).create_extended(tolerance));
3664
3666 query_bounding_boxes);
3667 const auto &[indices_ranks, offsets] =
3668 distributed_tree.query(bb_intersect);
3669
3670 for (unsigned long int i = 0; i < offsets.size() - 1; ++i)
3671 {
3672 std::set<unsigned int> my_ranks;
3673 for (int j = offsets[i]; j < offsets[i + 1]; ++j)
3674 my_ranks.insert(indices_ranks[j].second);
3675
3676 for (const auto rank : my_ranks)
3677 ranks_and_indices.emplace_back(rank, i);
3678 }
3679 }
3680 else
3681 {
3682 // global_bboxes.size()>1
3683 process_bboxes();
3684 }
3685 }
3686 else
3687 {
3688 // No ArborX
3689 process_bboxes();
3690 }
3691
3692
3693 // convert to CRS
3694 std::sort(ranks_and_indices.begin(), ranks_and_indices.end());
3695
3696 std::vector<unsigned int> ranks;
3697 std::vector<unsigned int> ptr;
3698 std::vector<unsigned int> indices;
3699
3700 unsigned int current_rank = numbers::invalid_unsigned_int;
3701
3702 for (const std::pair<unsigned int, unsigned int> &i : ranks_and_indices)
3703 {
3704 if (current_rank != i.first)
3705 {
3706 current_rank = i.first;
3707 ranks.push_back(current_rank);
3708 ptr.push_back(indices.size());
3709 }
3710
3711 indices.push_back(i.second);
3712 }
3713 ptr.push_back(indices.size());
3714
3715 return {std::move(ranks), std::move(ptr), std::move(indices)};
3716 }
3717
3718
3719
3720 template <int dim, int spacedim>
3721 std::vector<
3722 std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
3723 Point<dim>>>
3725 const Cache<dim, spacedim> &cache,
3726 const Point<spacedim> &point,
3728 const std::vector<bool> &marked_vertices,
3729 const double tolerance,
3730 const bool enforce_unique_mapping)
3731 {
3732 std::vector<
3733 std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
3734 Point<dim>>>
3735 locally_owned_active_cells_around_point;
3736
3737 const auto first_cell = GridTools::find_active_cell_around_point(
3738 cache.get_mapping(),
3739 cache.get_triangulation(),
3740 point,
3741 cache.get_vertex_to_cell_map(),
3743 cell_hint,
3744 marked_vertices,
3746 tolerance,
3748
3749 const unsigned int my_rank = Utilities::MPI::this_mpi_process(
3751
3752 cell_hint = first_cell.first;
3753 if (cell_hint.state() == IteratorState::valid)
3754 {
3755 const auto active_cells_around_point =
3757 cache.get_mapping(),
3758 cache.get_triangulation(),
3759 point,
3760 tolerance,
3761 first_cell,
3762 &cache.get_vertex_to_cell_map());
3763
3764 if (enforce_unique_mapping)
3765 {
3766 // check if the rank of this process is the lowest of all cells
3767 // if not, the other process will handle this cell and we don't
3768 // have to do here anything in the case of unique mapping
3769 unsigned int lowes_rank = numbers::invalid_unsigned_int;
3770
3771 for (const auto &cell : active_cells_around_point)
3772 lowes_rank = std::min(lowes_rank, cell.first->subdomain_id());
3773
3774 if (lowes_rank != my_rank)
3775 return {};
3776 }
3777
3778 locally_owned_active_cells_around_point.reserve(
3779 active_cells_around_point.size());
3780
3781 for (const auto &cell : active_cells_around_point)
3782 if (cell.first->is_locally_owned())
3783 locally_owned_active_cells_around_point.push_back(cell);
3784 }
3785
3786 std::sort(locally_owned_active_cells_around_point.begin(),
3787 locally_owned_active_cells_around_point.end(),
3788 [](const auto &a, const auto &b) { return a.first < b.first; });
3789
3790 if (enforce_unique_mapping &&
3791 locally_owned_active_cells_around_point.size() > 1)
3792 // in the case of unique mapping, we only need a single cell
3793 return {locally_owned_active_cells_around_point.front()};
3794 else
3795 return locally_owned_active_cells_around_point;
3796 }
3797
3798 template <int dim, int spacedim>
3803
3804 template <int dim, int spacedim>
3805 void
3807 {
3808 // before reshuffeling the data check if data.recv_components and
3809 // n_searched_points are in a valid state.
3810 Assert(n_searched_points != numbers::invalid_unsigned_int,
3812 Assert(recv_components.empty() ||
3813 std::get<1>(*std::max_element(recv_components.begin(),
3814 recv_components.end(),
3815 [](const auto &a, const auto &b) {
3816 return std::get<1>(a) <
3817 std::get<1>(b);
3818 })) < n_searched_points,
3820
3821 send_ranks.clear();
3822 recv_ranks.clear();
3823 send_ptrs.clear();
3824 recv_ptrs.clear();
3825
3826 if (true)
3827 {
3828 // sort according to rank (and point index and cell) -> make
3829 // deterministic
3830 std::sort(send_components.begin(),
3831 send_components.end(),
3832 [&](const auto &a, const auto &b) {
3833 if (std::get<1>(a) != std::get<1>(b)) // rank
3834 return std::get<1>(a) < std::get<1>(b);
3835
3836 if (std::get<2>(a) != std::get<2>(b)) // point index
3837 return std::get<2>(a) < std::get<2>(b);
3838
3839 return std::get<0>(a) < std::get<0>(b); // cell
3840 });
3841
3842 // perform enumeration and extract rank information
3843 for (unsigned int i = 0, dummy = numbers::invalid_unsigned_int;
3844 i < send_components.size();
3845 ++i)
3846 {
3847 std::get<5>(send_components[i]) = i;
3848
3849 if (dummy != std::get<1>(send_components[i]))
3850 {
3851 dummy = std::get<1>(send_components[i]);
3852 send_ranks.push_back(dummy);
3853 send_ptrs.push_back(i);
3854 }
3855 }
3856 send_ptrs.push_back(send_components.size());
3857
3858 // sort according to cell, rank, point index (while keeping
3859 // partial ordering)
3860 std::sort(send_components.begin(),
3861 send_components.end(),
3862 [&](const auto &a, const auto &b) {
3863 if (std::get<0>(a) != std::get<0>(b))
3864 return std::get<0>(a) < std::get<0>(b); // cell
3865
3866 if (std::get<1>(a) != std::get<1>(b))
3867 return std::get<1>(a) < std::get<1>(b); // rank
3868
3869 if (std::get<2>(a) != std::get<2>(b))
3870 return std::get<2>(a) < std::get<2>(b); // point index
3871
3872 return std::get<5>(a) < std::get<5>(b); // enumeration
3873 });
3874 }
3875
3876 if (recv_components.size() > 0)
3877 {
3878 // sort according to rank (and point index) -> make deterministic
3879 std::sort(recv_components.begin(),
3880 recv_components.end(),
3881 [&](const auto &a, const auto &b) {
3882 if (std::get<0>(a) != std::get<0>(b))
3883 return std::get<0>(a) < std::get<0>(b); // rank
3884
3885 return std::get<1>(a) < std::get<1>(b); // point index
3886 });
3887
3888 // perform enumeration and extract rank information
3889 for (unsigned int i = 0, dummy = numbers::invalid_unsigned_int;
3890 i < recv_components.size();
3891 ++i)
3892 {
3893 std::get<2>(recv_components[i]) = i;
3894
3895 if (dummy != std::get<0>(recv_components[i]))
3896 {
3897 dummy = std::get<0>(recv_components[i]);
3898 recv_ranks.push_back(dummy);
3899 recv_ptrs.push_back(i);
3900 }
3901 }
3902 recv_ptrs.push_back(recv_components.size());
3903
3904 // sort according to point index and rank (while keeping partial
3905 // ordering)
3906 std::sort(recv_components.begin(),
3907 recv_components.end(),
3908 [&](const auto &a, const auto &b) {
3909 if (std::get<1>(a) != std::get<1>(b))
3910 return std::get<1>(a) < std::get<1>(b); // point index
3911
3912 if (std::get<0>(a) != std::get<0>(b))
3913 return std::get<0>(a) < std::get<0>(b); // rank
3914
3915 return std::get<2>(a) < std::get<2>(b); // enumeration
3916 });
3917 }
3918 }
3919
3920
3921
3922 template <int dim, int spacedim>
3926 const std::vector<Point<spacedim>> &points,
3927 const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
3928 const std::vector<bool> &marked_vertices,
3929 const double tolerance,
3930 const bool perform_handshake,
3931 const bool enforce_unique_mapping)
3932 {
3934 result.n_searched_points = points.size();
3935
3936 auto &send_components = result.send_components;
3937 auto &recv_components = result.recv_components;
3938
3939 const auto comm = cache.get_triangulation().get_mpi_communicator();
3940
3941 const auto potential_owners = internal::guess_owners_of_entities(
3942 comm, global_bboxes, points, tolerance);
3943
3944 const auto &potential_owners_ranks = std::get<0>(potential_owners);
3945 const auto &potential_owners_ptrs = std::get<1>(potential_owners);
3946 const auto &potential_owners_indices = std::get<2>(potential_owners);
3947
3948 auto cell_hint = cache.get_triangulation().begin_active();
3949
3950 const auto translate = [&](const unsigned int other_rank) {
3951 const auto ptr = std::find(potential_owners_ranks.begin(),
3952 potential_owners_ranks.end(),
3953 other_rank);
3954
3955 Assert(ptr != potential_owners_ranks.end(), ExcInternalError());
3956
3957 const auto other_rank_index =
3958 std::distance(potential_owners_ranks.begin(), ptr);
3959
3960 return other_rank_index;
3961 };
3962
3963 Assert(
3964 (marked_vertices.empty()) ||
3965 (marked_vertices.size() == cache.get_triangulation().n_vertices()),
3966 ExcMessage(
3967 "The marked_vertices vector has to be either empty or its size has "
3968 "to equal the number of vertices of the triangulation."));
3969
3970 using RequestType = std::vector<std::pair<unsigned int, Point<spacedim>>>;
3971 using AnswerType = std::vector<unsigned int>;
3972
3973 // In the case that a marked_vertices vector has been given and none
3974 // of its entries is true, we know that this process does not own
3975 // any of the incoming points (and it will not send any data) so
3976 // that we can take a short cut.
3977 const bool has_relevant_vertices =
3978 (marked_vertices.empty()) ||
3979 (std::find(marked_vertices.begin(), marked_vertices.end(), true) !=
3980 marked_vertices.end());
3981
3982 const auto create_request = [&](const unsigned int other_rank) {
3983 const auto other_rank_index = translate(other_rank);
3984
3985 RequestType request;
3986 request.reserve(potential_owners_ptrs[other_rank_index + 1] -
3987 potential_owners_ptrs[other_rank_index]);
3988
3989 for (unsigned int i = potential_owners_ptrs[other_rank_index];
3990 i < potential_owners_ptrs[other_rank_index + 1];
3991 ++i)
3992 request.emplace_back(potential_owners_indices[i],
3993 points[potential_owners_indices[i]]);
3994
3995 return request;
3996 };
3997
3998 const auto answer_request =
3999 [&](const unsigned int &other_rank,
4000 const RequestType &request) -> AnswerType {
4001 AnswerType answer(request.size(), 0);
4002
4003 if (has_relevant_vertices)
4004 {
4005 cell_hint = cache.get_triangulation().begin_active();
4006
4007 for (unsigned int i = 0; i < request.size(); ++i)
4008 {
4009 const auto &index_and_point = request[i];
4010
4011 const auto cells_and_reference_positions =
4013 cache,
4014 index_and_point.second,
4015 cell_hint,
4016 marked_vertices,
4017 tolerance,
4018 enforce_unique_mapping);
4019
4020 if (cell_hint.state() != IteratorState::valid)
4021 cell_hint = cache.get_triangulation().begin_active();
4022
4023 for (const auto &cell_and_reference_position :
4024 cells_and_reference_positions)
4025 {
4026 const auto cell = cell_and_reference_position.first;
4027 auto reference_position =
4028 cell_and_reference_position.second;
4029
4030 reference_position =
4031 cell->reference_cell().closest_point(reference_position);
4032
4033 send_components.emplace_back(
4034 std::pair<int, int>(cell->level(), cell->index()),
4035 other_rank,
4036 index_and_point.first,
4037 reference_position,
4038 index_and_point.second,
4040 }
4041
4042 answer[i] = cells_and_reference_positions.size();
4043 }
4044 }
4045
4046 if (perform_handshake)
4047 return answer;
4048 else
4049 return {};
4050 };
4051
4052 const auto process_answer = [&](const unsigned int other_rank,
4053 const AnswerType &answer) {
4054 if (perform_handshake)
4055 {
4056 const auto other_rank_index = translate(other_rank);
4057
4058 for (unsigned int i = 0; i < answer.size(); ++i)
4059 for (unsigned int j = 0; j < answer[i]; ++j)
4060 recv_components.emplace_back(
4061 other_rank,
4062 potential_owners_indices
4063 [i + potential_owners_ptrs[other_rank_index]],
4065 }
4066 };
4067
4068 Utilities::MPI::ConsensusAlgorithms::selector<RequestType, AnswerType>(
4069 potential_owners_ranks,
4070 create_request,
4071 answer_request,
4072 process_answer,
4073 comm);
4074
4075 result.finalize_setup();
4076
4077 return result;
4078 }
4079
4080
4081
4082 template <int structdim, int spacedim>
4083 template <int dim>
4084 DistributedComputePointLocationsInternal<dim, spacedim>
4087 const unsigned int n_points_1D,
4088 const Triangulation<dim, spacedim> &tria,
4089 const Mapping<dim, spacedim> &mapping,
4090 std::vector<Quadrature<spacedim>> *mapped_quadratures_recv_comp,
4091 const bool consistent_numbering_of_sender_and_receiver) const
4092 {
4093 using CellIterator =
4095
4096 if (mapped_quadratures_recv_comp != nullptr)
4097 {
4098 AssertDimension(mapped_quadratures_recv_comp->size(), 0);
4099 mapped_quadratures_recv_comp->reserve(recv_components.size());
4100 }
4101
4103 spacedim>
4104 result;
4105
4106 // We need quadrature rules for the intersections. We are using a
4107 // QGaussSimplex quadrature rule since CGAL always returns simplices
4108 // as intersections.
4109 const QGaussSimplex<structdim> quadrature(n_points_1D);
4110
4111 // Resulting quadrature points get different indices. In the case the
4112 // requested intersections are unique also the resulting quadrature
4113 // points are unique and we can simply number the points in an
4114 // ascending way.
4115 for (const auto &recv_component : recv_components)
4116 {
4117 // dependent on the size of the intersection an empty quadrature
4118 // is returned. Therefore, we have to compute the quadrature also
4119 // here.
4120 const Quadrature<spacedim> &quad =
4122 std::get<2>(recv_component));
4123
4124 for (unsigned int i = 0; i < quad.size(); ++i)
4125 {
4126 // the third component of result.recv_components is not needed
4127 // before finalize_setup.
4128 result.recv_components.emplace_back(
4129 std::get<0>(recv_component),
4130 result.recv_components.size(), // number of point
4132 }
4133
4134 // append quadrature
4135 if (mapped_quadratures_recv_comp != nullptr)
4136 mapped_quadratures_recv_comp->push_back(quad);
4137 }
4138
4139 // since empty quadratures might be present we have to set the number
4140 // of searched points after inserting the point indices into
4141 // recv_components
4142 result.n_searched_points = result.recv_components.size();
4143
4144 // send_ranks, counter, and indices_of_rank is only needed if
4145 // consistent_numbering_of_sender_and_receiver==true
4146 // indices_of_rank is always empty if deal.II is compiled without MPI
4147 std::map<unsigned int, std::vector<unsigned int>> indices_of_rank;
4148 std::map<unsigned int, unsigned int> counter;
4149 std::set<unsigned int> send_ranks;
4150 if (consistent_numbering_of_sender_and_receiver)
4151 {
4152 for (const auto &sc : send_components)
4153 send_ranks.insert(std::get<1>(sc));
4154
4155 for (const auto rank : send_ranks)
4156 counter[rank] = 0;
4157
4158 // indices assigned at recv side needed to fill send_components
4159 indices_of_rank = communicate_indices(result.recv_components,
4160 tria.get_mpi_communicator());
4161 }
4162
4163 for (const auto &send_component : send_components)
4164 {
4165 const CellIterator cell(&tria,
4166 std::get<0>(send_component).first,
4167 std::get<0>(send_component).second);
4168
4169 const Quadrature<spacedim> &quad =
4171 std::get<3>(send_component));
4172
4173 const auto rank = std::get<1>(send_component);
4174
4175 for (unsigned int q = 0; q < quad.size(); ++q)
4176 {
4177 // the fifth component of result.send_components is filled
4178 // during sorting the data and initializing the CRS structures
4179 result.send_components.emplace_back(std::make_tuple(
4180 std::get<0>(send_component),
4181 rank,
4182 indices_of_rank.empty() ?
4183 result.send_components.size() :
4184 indices_of_rank.at(rank)[counter.at(rank)],
4185 mapping.transform_real_to_unit_cell(cell, quad.point(q)),
4186 quad.point(q),
4188
4189 if (!indices_of_rank.empty())
4190 ++counter[rank];
4191 }
4192 }
4193
4194 result.finalize_setup();
4195
4196 return result;
4197 }
4198
4199
4200
4201 template <int structdim, int spacedim>
4202 std::map<unsigned int, std::vector<unsigned int>>
4205 [[maybe_unused]] const std::vector<
4206 std::tuple<unsigned int, unsigned int, unsigned int>>
4207 &point_recv_components,
4208 [[maybe_unused]] const MPI_Comm comm) const
4209 {
4210#ifndef DEAL_II_WITH_MPI
4211 Assert(false, ExcNeedsMPI());
4212 return {};
4213#else
4214 // since we are converting to DistributedComputePointLocationsInternal
4215 // we use the RPE tag
4216 const auto mpi_tag =
4218
4219 const unsigned int my_rank = Utilities::MPI::this_mpi_process(comm);
4220
4221 std::set<unsigned int> send_ranks;
4222 for (const auto &sc : send_components)
4223 send_ranks.insert(std::get<1>(sc));
4224 std::set<unsigned int> recv_ranks;
4225 for (const auto &rc : recv_components)
4226 recv_ranks.insert(std::get<0>(rc));
4227
4228 std::vector<MPI_Request> requests;
4229 requests.reserve(send_ranks.size());
4230
4231 // rank to used indices on the rank needed on sending side
4232 std::map<unsigned int, std::vector<unsigned int>> indices_of_rank;
4233 indices_of_rank[my_rank] = std::vector<unsigned int>();
4234
4235 // rank to used indices on the rank known on recv side
4236 std::map<unsigned int, std::vector<unsigned int>> send_indices_of_rank;
4237 for (const auto rank : recv_ranks)
4238 if (rank != my_rank)
4239 send_indices_of_rank[rank] = std::vector<unsigned int>();
4240
4241 // fill the maps
4242 for (const auto &point_recv_component : point_recv_components)
4243 {
4244 const auto rank = std::get<0>(point_recv_component);
4245 const auto idx = std::get<1>(point_recv_component);
4246
4247 if (rank == my_rank)
4248 indices_of_rank[rank].emplace_back(idx);
4249 else
4250 send_indices_of_rank[rank].emplace_back(idx);
4251 }
4252
4253 // send indices to the ranks we normally receive from
4254 for (const auto rank : recv_ranks)
4255 {
4256 if (rank == my_rank)
4257 continue;
4258
4259 auto buffer = Utilities::pack(send_indices_of_rank[rank], false);
4260
4261 requests.push_back(MPI_Request());
4262
4263 const int ierr = MPI_Isend(buffer.data(),
4264 buffer.size(),
4265 MPI_CHAR,
4266 rank,
4267 mpi_tag,
4268 comm,
4269 &requests.back());
4270 AssertThrowMPI(ierr);
4271 }
4272
4273 // receive indices at the ranks we normally send from
4274 for (const auto rank : send_ranks)
4275 {
4276 if (rank == my_rank)
4277 continue;
4278
4279 MPI_Status status;
4280 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, comm, &status);
4281 AssertThrowMPI(ierr);
4282
4283 int message_length;
4284 ierr = MPI_Get_count(&status, MPI_CHAR, &message_length);
4285 AssertThrowMPI(ierr);
4286
4287 std::vector<char> buffer(message_length);
4288
4289 ierr = MPI_Recv(buffer.data(),
4290 buffer.size(),
4291 MPI_CHAR,
4292 status.MPI_SOURCE,
4293 mpi_tag,
4294 comm,
4295 MPI_STATUS_IGNORE);
4296 AssertThrowMPI(ierr);
4297
4298 indices_of_rank[status.MPI_SOURCE] =
4299 Utilities::unpack<std::vector<unsigned int>>(buffer, false);
4300 }
4301
4302 // make sure all messages have been sent
4303 const int ierr =
4304 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
4305 AssertThrowMPI(ierr);
4306
4307 return indices_of_rank;
4308#endif
4309 }
4310
4311
4312
4313 template <int structdim, int dim, int spacedim>
4316 const Cache<dim, spacedim> &cache,
4317 const std::vector<std::vector<Point<spacedim>>> &intersection_requests,
4318 const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
4319 const std::vector<bool> &marked_vertices,
4320 const double tolerance)
4321 {
4322 using IntersectionRequest = std::vector<Point<spacedim>>;
4323
4324 using IntersectionAnswer =
4326 structdim,
4327 spacedim>::IntersectionType;
4328
4329 const auto comm = cache.get_triangulation().get_mpi_communicator();
4330
4332 result;
4333
4334 auto &send_components = result.send_components;
4335 auto &recv_components = result.recv_components;
4336 auto &recv_ptrs = result.recv_ptrs;
4337
4338 // search for potential owners
4339 const auto potential_owners = internal::guess_owners_of_entities(
4340 comm, global_bboxes, intersection_requests, tolerance);
4341
4342 const auto &potential_owners_ranks = std::get<0>(potential_owners);
4343 const auto &potential_owners_ptrs = std::get<1>(potential_owners);
4344 const auto &potential_owners_indices = std::get<2>(potential_owners);
4345
4346 const auto translate = [&](const unsigned int other_rank) {
4347 const auto ptr = std::find(potential_owners_ranks.begin(),
4348 potential_owners_ranks.end(),
4349 other_rank);
4350
4351 Assert(ptr != potential_owners_ranks.end(), ExcInternalError());
4352
4353 const auto other_rank_index =
4354 std::distance(potential_owners_ranks.begin(), ptr);
4355
4356 return other_rank_index;
4357 };
4358
4359 Assert(
4360 (marked_vertices.empty()) ||
4361 (marked_vertices.size() == cache.get_triangulation().n_vertices()),
4362 ExcMessage(
4363 "The marked_vertices vector has to be either empty or its size has "
4364 "to equal the number of vertices of the triangulation."));
4365
4366 // In the case that a marked_vertices vector has been given and none
4367 // of its entries is true, we know that this process does not own
4368 // any of the incoming points (and it will not send any data) so
4369 // that we can take a short cut.
4370 const bool has_relevant_vertices =
4371 (marked_vertices.empty()) ||
4372 (std::find(marked_vertices.begin(), marked_vertices.end(), true) !=
4373 marked_vertices.end());
4374
4375 // intersection between two cells:
4376 // One rank requests all intersections of owning cell:
4377 // owning cell index, cgal vertices of cell
4378 using RequestType =
4379 std::vector<std::pair<unsigned int, IntersectionRequest>>;
4380 // Other ranks send back all found intersections for requesting cell:
4381 // requesting cell index, cgal vertices of found intersections
4382 using AnswerType =
4383 std::vector<std::pair<unsigned int, IntersectionAnswer>>;
4384
4385 const auto create_request = [&](const unsigned int other_rank) {
4386 const auto other_rank_index = translate(other_rank);
4387
4388 RequestType request;
4389 request.reserve(potential_owners_ptrs[other_rank_index + 1] -
4390 potential_owners_ptrs[other_rank_index]);
4391
4392 for (unsigned int i = potential_owners_ptrs[other_rank_index];
4393 i < potential_owners_ptrs[other_rank_index + 1];
4394 ++i)
4395 request.emplace_back(
4396 potential_owners_indices[i],
4397 intersection_requests[potential_owners_indices[i]]);
4398
4399 return request;
4400 };
4401
4402
4403 // TODO: this is potentially useful in many cases and it would be nice to
4404 // have cache.get_locally_owned_cell_bounding_boxes_rtree(marked_vertices)
4405 const auto construct_locally_owned_cell_bounding_boxes_rtree =
4406 [&cache](const std::vector<bool> &marked_verts) {
4407 const auto cell_marked = [&marked_verts](const auto &cell) {
4408 for (const unsigned int v : cell->vertex_indices())
4409 if (marked_verts[cell->vertex_index(v)])
4410 return true;
4411 return false;
4412 };
4413
4414 const auto &boxes_and_cells =
4416
4417 if (marked_verts.empty())
4418 return boxes_and_cells;
4419
4420 std::vector<std::pair<
4423 potential_boxes_and_cells;
4424
4425 for (const auto &box_and_cell : boxes_and_cells)
4426 if (cell_marked(box_and_cell.second))
4427 potential_boxes_and_cells.emplace_back(box_and_cell);
4428
4429 return pack_rtree(potential_boxes_and_cells);
4430 };
4431
4432
4433 RTree<
4434 std::pair<BoundingBox<spacedim>,
4436 marked_cell_tree;
4437
4438 const auto answer_request =
4439 [&]([[maybe_unused]] const unsigned int &other_rank,
4440 const RequestType &request) -> AnswerType {
4441 AnswerType answer;
4442
4443 if (has_relevant_vertices)
4444 {
4445 if (marked_cell_tree.empty())
4446 {
4447 marked_cell_tree =
4448 construct_locally_owned_cell_bounding_boxes_rtree(
4449 marked_vertices);
4450 }
4451
4452 // process requests
4453 for (unsigned int i = 0; i < request.size(); ++i)
4454 {
4455 // create a bounding box with tolerance
4456 const auto bb = BoundingBox<spacedim>(request[i].second)
4457 .create_extended(tolerance);
4458
4459 for ([[maybe_unused]] const auto &box_cell :
4460 marked_cell_tree |
4461 boost::geometry::index::adaptors::queried(
4462 boost::geometry::index::intersects(bb)))
4463 {
4464#ifdef DEAL_II_WITH_CGAL
4465 const auto &cell = box_cell.second;
4466 const auto &request_index = request[i].first;
4467 auto requested_intersection = request[i].second;
4468 CGALWrappers::resort_dealii_vertices_to_cgal_order(
4469 structdim, requested_intersection);
4470
4471 const auto &try_intersection =
4472 CGALWrappers::get_vertices_in_cgal_order(
4473 cell, cache.get_mapping());
4474
4475 const auto &found_intersections = CGALWrappers::
4476 compute_intersection_of_cells<dim, structdim, spacedim>(
4477 try_intersection, requested_intersection, tolerance);
4478
4479 if (found_intersections.size() > 0)
4480 {
4481 for (const auto &found_intersection :
4482 found_intersections)
4483 {
4484 answer.emplace_back(request_index,
4485 found_intersection);
4486
4487 send_components.emplace_back(
4488 std::make_pair(cell->level(), cell->index()),
4489 other_rank,
4490 request_index,
4491 found_intersection);
4492 }
4493 }
4494#else
4495 Assert(false, ExcNeedsCGAL());
4496#endif
4497 }
4498 }
4499 }
4500
4501 return answer;
4502 };
4503
4504 const auto process_answer = [&](const unsigned int other_rank,
4505 const AnswerType &answer) {
4506 for (unsigned int i = 0; i < answer.size(); ++i)
4507 recv_components.emplace_back(other_rank,
4508 answer[i].first,
4509 answer[i].second);
4510 };
4511
4512 Utilities::MPI::ConsensusAlgorithms::selector<RequestType, AnswerType>(
4513 potential_owners_ranks,
4514 create_request,
4515 answer_request,
4516 process_answer,
4517 comm);
4518
4519 // sort according to 1) intersection index and 2) rank (keeping the order
4520 // of recv components with same indices and ranks)
4521 std::stable_sort(recv_components.begin(),
4522 recv_components.end(),
4523 [&](const auto &a, const auto &b) {
4524 // intersection index
4525 if (std::get<1>(a) != std::get<1>(b))
4526 return std::get<1>(a) < std::get<1>(b);
4527
4528 // rank
4529 return std::get<0>(a) < std::get<0>(b);
4530 });
4531
4532 // sort according to 1) rank and 2) intersection index (keeping the
4533 // order of recv components with same indices and ranks)
4534 std::stable_sort(send_components.begin(),
4535 send_components.end(),
4536 [&](const auto &a, const auto &b) {
4537 // rank
4538 if (std::get<1>(a) != std::get<1>(b))
4539 return std::get<1>(a) < std::get<1>(b);
4540
4541 // intersection idx
4542 return std::get<2>(a) < std::get<2>(b);
4543 });
4544
4545 // construct recv_ptrs
4546 recv_ptrs.assign(intersection_requests.size() + 1, 0);
4547 for (const auto &rc : recv_components)
4548 ++recv_ptrs[std::get<1>(rc) + 1];
4549 for (unsigned int i = 0; i < intersection_requests.size(); ++i)
4550 recv_ptrs[i + 1] += recv_ptrs[i];
4551
4552 return result;
4553 }
4554
4555 } // namespace internal
4556
4557
4558
4559 template <int spacedim>
4560 unsigned int
4561 find_closest_vertex(const std::map<unsigned int, Point<spacedim>> &vertices,
4562 const Point<spacedim> &p)
4563 {
4564 auto id_and_v = std::min_element(
4565 vertices.begin(),
4566 vertices.end(),
4567 [&](const std::pair<const unsigned int, Point<spacedim>> &p1,
4568 const std::pair<const unsigned int, Point<spacedim>> &p2) -> bool {
4569 return p1.second.distance(p) < p2.second.distance(p);
4570 });
4571 return id_and_v->first;
4572 }
4573
4574
4575 template <int dim, int spacedim>
4576 std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
4577 Point<dim>>
4579 const Cache<dim, spacedim> &cache,
4580 const Point<spacedim> &p,
4582 &cell_hint,
4583 const std::vector<bool> &marked_vertices,
4584 const double tolerance)
4585 {
4586 const auto &mesh = cache.get_triangulation();
4587 const auto &mapping = cache.get_mapping();
4588 const auto &vertex_to_cells = cache.get_vertex_to_cell_map();
4589 const auto &vertex_to_cell_centers =
4591 const auto &used_vertices_rtree = cache.get_used_vertices_rtree();
4592
4593 return find_active_cell_around_point(mapping,
4594 mesh,
4595 p,
4596 vertex_to_cells,
4597 vertex_to_cell_centers,
4598 cell_hint,
4599 marked_vertices,
4600 used_vertices_rtree,
4601 tolerance);
4602 }
4603
4604 template <int spacedim>
4605 std::vector<std::vector<BoundingBox<spacedim>>>
4607 [[maybe_unused]] const std::vector<BoundingBox<spacedim>> &local_bboxes,
4608 [[maybe_unused]] const MPI_Comm mpi_communicator)
4609 {
4610#ifndef DEAL_II_WITH_MPI
4611 Assert(false,
4612 ExcMessage(
4613 "GridTools::exchange_local_bounding_boxes() requires MPI."));
4614 return {};
4615#else
4616 // Step 1: preparing data to be sent
4617 unsigned int n_bboxes = local_bboxes.size();
4618 // Dimension of the array to be exchanged (number of double)
4619 int n_local_data = 2 * spacedim * n_bboxes;
4620 // data array stores each entry of each point describing the bounding
4621 // boxes
4622 std::vector<double> loc_data_array(n_local_data);
4623 for (unsigned int i = 0; i < n_bboxes; ++i)
4624 for (unsigned int d = 0; d < spacedim; ++d)
4625 {
4626 // Extracting the coordinates of each boundary point
4627 loc_data_array[2 * i * spacedim + d] =
4628 local_bboxes[i].get_boundary_points().first[d];
4629 loc_data_array[2 * i * spacedim + spacedim + d] =
4630 local_bboxes[i].get_boundary_points().second[d];
4631 }
4632
4633 // Step 2: exchanging the size of local data
4634 unsigned int n_procs = Utilities::MPI::n_mpi_processes(mpi_communicator);
4635
4636 // Vector to store the size of loc_data_array for every process
4637 std::vector<int> size_all_data(n_procs);
4638
4639 // Exchanging the number of bboxes
4640 int ierr = MPI_Allgather(&n_local_data,
4641 1,
4642 MPI_INT,
4643 size_all_data.data(),
4644 1,
4645 MPI_INT,
4646 mpi_communicator);
4647 AssertThrowMPI(ierr);
4648
4649 // Now computing the displacement, relative to recvbuf,
4650 // at which to store the incoming data
4651 std::vector<int> rdispls(n_procs);
4652 rdispls[0] = 0;
4653 for (unsigned int i = 1; i < n_procs; ++i)
4654 rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
4655
4656 // Step 3: exchange the data and bounding boxes:
4657 // Allocating a vector to contain all the received data
4658 std::vector<double> data_array(rdispls.back() + size_all_data.back());
4659
4660 ierr = MPI_Allgatherv(loc_data_array.data(),
4661 n_local_data,
4662 MPI_DOUBLE,
4663 data_array.data(),
4664 size_all_data.data(),
4665 rdispls.data(),
4666 MPI_DOUBLE,
4667 mpi_communicator);
4668 AssertThrowMPI(ierr);
4669
4670 // Step 4: create the array of bboxes for output
4671 std::vector<std::vector<BoundingBox<spacedim>>> global_bboxes(n_procs);
4672 unsigned int begin_idx = 0;
4673 for (unsigned int i = 0; i < n_procs; ++i)
4674 {
4675 // Number of local bounding boxes
4676 unsigned int n_bbox_i = size_all_data[i] / (spacedim * 2);
4677 global_bboxes[i].resize(n_bbox_i);
4678 for (unsigned int bbox = 0; bbox < n_bbox_i; ++bbox)
4679 {
4680 Point<spacedim> p1, p2; // boundary points for bbox
4681 for (unsigned int d = 0; d < spacedim; ++d)
4682 {
4683 p1[d] = data_array[begin_idx + 2 * bbox * spacedim + d];
4684 p2[d] =
4685 data_array[begin_idx + 2 * bbox * spacedim + spacedim + d];
4686 }
4687 BoundingBox<spacedim> loc_bbox(std::make_pair(p1, p2));
4688 global_bboxes[i][bbox] = loc_bbox;
4689 }
4690 // Shifting the first index to the start of the next vector
4691 begin_idx += size_all_data[i];
4692 }
4693 return global_bboxes;
4694#endif // DEAL_II_WITH_MPI
4695 }
4696
4697
4698
4699 template <int spacedim>
4702 const std::vector<BoundingBox<spacedim>> &local_description,
4703 [[maybe_unused]] const MPI_Comm mpi_communicator)
4704 {
4705#ifndef DEAL_II_WITH_MPI
4706 // Building a tree with the only boxes available without MPI
4707 std::vector<std::pair<BoundingBox<spacedim>, unsigned int>> boxes_index(
4708 local_description.size());
4709 // Adding to each box the rank of the process owning it
4710 for (unsigned int i = 0; i < local_description.size(); ++i)
4711 boxes_index[i] = std::make_pair(local_description[i], 0u);
4712 return pack_rtree(boxes_index);
4713#else
4714 // Exchanging local bounding boxes
4715 const std::vector<std::vector<BoundingBox<spacedim>>> global_bboxes =
4716 Utilities::MPI::all_gather(mpi_communicator, local_description);
4717
4718 // Preparing to flatten the vector
4719 const unsigned int n_procs =
4720 Utilities::MPI::n_mpi_processes(mpi_communicator);
4721 // The i'th element of the following vector contains the index of the
4722 // first local bounding box from the process of rank i
4723 std::vector<unsigned int> bboxes_position(n_procs);
4724
4725 unsigned int tot_bboxes = 0;
4726 for (const auto &process_bboxes : global_bboxes)
4727 tot_bboxes += process_bboxes.size();
4728
4729 // Now flattening the vector
4730 std::vector<std::pair<BoundingBox<spacedim>, unsigned int>>
4731 flat_global_bboxes;
4732 flat_global_bboxes.reserve(tot_bboxes);
4733 unsigned int process_index = 0;
4734 for (const auto &process_bboxes : global_bboxes)
4735 {
4736 // Initialize a vector containing bounding boxes and rank of a process
4737 std::vector<std::pair<BoundingBox<spacedim>, unsigned int>>
4738 boxes_and_indices(process_bboxes.size());
4739
4740 // Adding to each box the rank of the process owning it
4741 for (unsigned int i = 0; i < process_bboxes.size(); ++i)
4742 boxes_and_indices[i] =
4743 std::make_pair(process_bboxes[i], process_index);
4744
4745 flat_global_bboxes.insert(flat_global_bboxes.end(),
4746 boxes_and_indices.begin(),
4747 boxes_and_indices.end());
4748
4749 ++process_index;
4750 }
4751
4752 // Build a tree out of the bounding boxes. We avoid using the
4753 // insert method so that boost uses the packing algorithm
4754 return RTree<std::pair<BoundingBox<spacedim>, unsigned int>>(
4755 flat_global_bboxes.begin(), flat_global_bboxes.end());
4756#endif // DEAL_II_WITH_MPI
4757 }
4758
4759
4760
4761 template <int dim, int spacedim>
4762 void
4764 const Triangulation<dim, spacedim> &tria,
4765 std::map<unsigned int, std::vector<unsigned int>> &coinciding_vertex_groups,
4766 std::map<unsigned int, unsigned int> &vertex_to_coinciding_vertex_group)
4767 {
4768 // 1) determine for each vertex a vertex it coincides with and
4769 // put it into a map
4770 {
4771 // loop over all periodic face pairs
4772 for (const auto &pair : tria.get_periodic_face_map())
4773 {
4774 if (pair.first.first->level() != pair.second.first.first->level())
4775 continue;
4776
4777 const auto face_a = pair.first.first->face(pair.first.second);
4778 const auto face_b =
4779 pair.second.first.first->face(pair.second.first.second);
4780 const auto reference_cell = pair.first.first->reference_cell();
4781 const auto face_reference_cell = face_a->reference_cell();
4782 const auto combined_orientation = pair.second.second;
4783 const auto inverse_combined_orientation =
4784 face_reference_cell.get_inverse_combined_orientation(
4785 combined_orientation);
4786
4787 AssertDimension(face_a->n_vertices(), face_b->n_vertices());
4788
4789 // loop over all vertices on face
4790 for (unsigned int i = 0; i < face_a->n_vertices(); ++i)
4791 {
4792 // find the right local vertex index for the second face
4793 const unsigned int j =
4794 reference_cell.standard_to_real_face_vertex(
4795 i, pair.first.second, inverse_combined_orientation);
4796
4797 // get vertex indices and store in map
4798 const auto vertex_a = face_a->vertex_index(i);
4799 const auto vertex_b = face_b->vertex_index(j);
4800 unsigned int temp = std::min(vertex_a, vertex_b);
4801
4802 auto it_a = vertex_to_coinciding_vertex_group.find(vertex_a);
4803 if (it_a != vertex_to_coinciding_vertex_group.end())
4804 temp = std::min(temp, it_a->second);
4805
4806 auto it_b = vertex_to_coinciding_vertex_group.find(vertex_b);
4807 if (it_b != vertex_to_coinciding_vertex_group.end())
4808 temp = std::min(temp, it_b->second);
4809
4810 if (it_a != vertex_to_coinciding_vertex_group.end())
4811 it_a->second = temp;
4812 else
4813 vertex_to_coinciding_vertex_group[vertex_a] = temp;
4814
4815 if (it_b != vertex_to_coinciding_vertex_group.end())
4816 it_b->second = temp;
4817 else
4818 vertex_to_coinciding_vertex_group[vertex_b] = temp;
4819 }
4820 }
4821
4822 // 2) compress map: let vertices point to the coinciding vertex with
4823 // the smallest index
4824 for (auto &p : vertex_to_coinciding_vertex_group)
4825 {
4826 if (p.first == p.second)
4827 continue;
4828 unsigned int temp = p.second;
4829 while (temp != vertex_to_coinciding_vertex_group[temp])
4830 temp = vertex_to_coinciding_vertex_group[temp];
4831 p.second = temp;
4832 }
4833
4834 // 3) create a map: smallest index of coinciding index -> all
4835 // coinciding indices
4836 for (auto p : vertex_to_coinciding_vertex_group)
4837 coinciding_vertex_groups[p.second] = {};
4838
4839 for (auto p : vertex_to_coinciding_vertex_group)
4840 coinciding_vertex_groups[p.second].push_back(p.first);
4841 }
4842 }
4843
4844
4845
4846 template <int dim, int spacedim>
4847 std::map<unsigned int, std::set<::types::subdomain_id>>
4849 const Triangulation<dim, spacedim> &tria)
4850 {
4851 if (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
4852 &tria) == nullptr) // nothing to do for a serial triangulation
4853 return {};
4854
4855 // 1) collect for each vertex on periodic faces all vertices it coincides
4856 // with
4857 std::map<unsigned int, std::vector<unsigned int>> coinciding_vertex_groups;
4858 std::map<unsigned int, unsigned int> vertex_to_coinciding_vertex_group;
4859
4861 coinciding_vertex_groups,
4862 vertex_to_coinciding_vertex_group);
4863
4864 // 2) collect vertices belonging to local cells
4865 std::vector<bool> vertex_of_own_cell(tria.n_vertices(), false);
4866 for (const auto &cell :
4868 for (const unsigned int v : cell->vertex_indices())
4869 vertex_of_own_cell[cell->vertex_index(v)] = true;
4870
4871 // 3) for each vertex belonging to a locally owned cell, find all ghost
4872 // neighbors (including the periodic own)
4873 std::map<unsigned int, std::set<types::subdomain_id>> result;
4874
4875 // loop over all active ghost cells
4876 for (const auto &cell : tria.active_cell_iterators())
4877 if (cell->is_ghost())
4878 {
4879 const types::subdomain_id owner = cell->subdomain_id();
4880
4881 // loop over all its vertices
4882 for (const unsigned int v : cell->vertex_indices())
4883 {
4884 // set owner if vertex belongs to a local cell
4885 if (vertex_of_own_cell[cell->vertex_index(v)])
4886 result[cell->vertex_index(v)].insert(owner);
4887
4888 // mark also nodes coinciding due to periodicity
4889 auto coinciding_vertex_group =
4890 vertex_to_coinciding_vertex_group.find(cell->vertex_index(v));
4891 if (coinciding_vertex_group !=
4892 vertex_to_coinciding_vertex_group.end())
4893 for (auto coinciding_vertex :
4894 coinciding_vertex_groups[coinciding_vertex_group->second])
4895 if (vertex_of_own_cell[coinciding_vertex])
4896 result[coinciding_vertex].insert(owner);
4897 }
4898 }
4899
4900 return result;
4901 }
4902
4903
4904
4905 namespace internal
4906 {
4907 template <int dim,
4908 unsigned int n_vertices,
4909 unsigned int n_sub_vertices,
4910 unsigned int n_configurations,
4911 unsigned int n_lines,
4912 unsigned int n_cols,
4913 typename value_type>
4914 void
4916 const std::array<unsigned int, n_configurations> &cut_line_table,
4918 const ndarray<unsigned int, n_lines, 2> &line_to_vertex_table,
4919 const std::vector<value_type> &ls_values,
4920 const std::vector<Point<dim>> &points,
4921 const std::vector<unsigned int> &mask,
4922 const double iso_level,
4923 const double tolerance,
4924 std::vector<Point<dim>> &vertices,
4925 std::vector<CellData<dim == 1 ? 1 : dim - 1>> &cells,
4926 const bool write_back_cell_data)
4927 {
4928 // inspired by https://graphics.stanford.edu/~mdfisher/MarchingCubes.html
4929
4930 constexpr unsigned int X = static_cast<unsigned int>(-1);
4931
4932 // determine configuration
4933 unsigned int configuration = 0;
4934 for (unsigned int v = 0; v < n_vertices; ++v)
4935 if (ls_values[mask[v]] < iso_level)
4936 configuration |= (1 << v);
4937
4938 // cell is not cut (nothing to do)
4939 if (cut_line_table[configuration] == 0)
4940 return;
4941
4942 // helper function to determine where an edge (between index i and j) is
4943 // cut - see also: http://paulbourke.net/geometry/polygonise/
4944 const auto interpolate = [&](const unsigned int i, const unsigned int j) {
4945 if (std::abs(iso_level - ls_values[mask[i]]) < tolerance)
4946 return points[mask[i]];
4947 if (std::abs(iso_level - ls_values[mask[j]]) < tolerance)
4948 return points[mask[j]];
4949 if (std::abs(ls_values[mask[i]] - ls_values[mask[j]]) < tolerance)
4950 return points[mask[i]];
4951
4952 const double mu = (iso_level - ls_values[mask[i]]) /
4953 (ls_values[mask[j]] - ls_values[mask[i]]);
4954
4955 return Point<dim>(points[mask[i]] +
4956 mu * (points[mask[j]] - points[mask[i]]));
4957 };
4958
4959 // determine the position where edges are cut (if they are cut)
4960 std::array<Point<dim>, n_lines> vertex_list_all;
4961 for (unsigned int l = 0; l < n_lines; ++l)
4962 if (cut_line_table[configuration] & (1 << l))
4963 vertex_list_all[l] =
4964 interpolate(line_to_vertex_table[l][0], line_to_vertex_table[l][1]);
4965
4966 // merge duplicate vertices if possible
4967 unsigned int local_vertex_count = 0;
4968 std::array<Point<dim>, n_lines> vertex_list_reduced;
4969 std::array<unsigned int, n_lines> local_remap;
4970 std::fill(local_remap.begin(), local_remap.end(), X);
4971 for (int i = 0; new_line_table[configuration][i] != X; ++i)
4972 if (local_remap[new_line_table[configuration][i]] == X)
4973 {
4974 vertex_list_reduced[local_vertex_count] =
4975 vertex_list_all[new_line_table[configuration][i]];
4976 local_remap[new_line_table[configuration][i]] = local_vertex_count;
4977 ++local_vertex_count;
4978 }
4979
4980 // write back vertices
4981 const unsigned int n_vertices_old = vertices.size();
4982 for (unsigned int i = 0; i < local_vertex_count; ++i)
4983 vertices.push_back(vertex_list_reduced[i]);
4984
4985 // write back cells
4986 if (write_back_cell_data && dim > 1)
4987 {
4988 for (unsigned int i = 0; new_line_table[configuration][i] != X;
4989 i += n_sub_vertices)
4990 {
4991 cells.resize(cells.size() + 1);
4992 cells.back().vertices.resize(n_sub_vertices);
4993
4994 for (unsigned int v = 0; v < n_sub_vertices; ++v)
4995 cells.back().vertices[v] =
4996 local_remap[new_line_table[configuration][i + v]] +
4997 n_vertices_old;
4998 }
4999 }
5000 }
5001 } // namespace internal
5002
5003
5004
5005 template <int dim, typename VectorType>
5007 const Mapping<dim, dim> &mapping,
5008 const FiniteElement<dim, dim> &fe,
5009 const unsigned int n_subdivisions,
5010 const double tolerance)
5011 : n_subdivisions(n_subdivisions)
5012 , tolerance(tolerance)
5013 , fe_values(mapping,
5014 fe,
5015 create_quadrature_rule(n_subdivisions),
5017 {}
5018
5019
5020
5021 template <int dim, typename VectorType>
5024 const unsigned int n_subdivisions)
5025 {
5026 std::vector<Point<dim>> quadrature_points;
5027
5028 if (dim == 1)
5029 {
5030 for (unsigned int i = 0; i <= n_subdivisions; ++i)
5031 quadrature_points.emplace_back(1.0 / n_subdivisions * i);
5032 }
5033 else if (dim == 2)
5034 {
5035 for (unsigned int j = 0; j <= n_subdivisions; ++j)
5036 for (unsigned int i = 0; i <= n_subdivisions; ++i)
5037 quadrature_points.emplace_back(1.0 / n_subdivisions * i,
5038 1.0 / n_subdivisions * j);
5039 }
5040 else
5041 {
5042 for (unsigned int k = 0; k <= n_subdivisions; ++k)
5043 for (unsigned int j = 0; j <= n_subdivisions; ++j)
5044 for (unsigned int i = 0; i <= n_subdivisions; ++i)
5045 quadrature_points.emplace_back(1.0 / n_subdivisions * i,
5046 1.0 / n_subdivisions * j,
5047 1.0 / n_subdivisions * k);
5048 }
5049
5050
5051 return {quadrature_points};
5052 }
5053
5054
5055
5056 template <int dim, typename VectorType>
5057 void
5059 const DoFHandler<dim> &background_dof_handler,
5060 const VectorType &ls_vector,
5061 const double iso_level,
5062 std::vector<Point<dim>> &vertices,
5063 std::vector<CellData<dim == 1 ? 1 : dim - 1>> &cells) const
5064 {
5066 dim > 1,
5067 ExcMessage(
5068 "Not implemented for dim==1. Use the alternative process()-function "
5069 "not returning a vector of CellData objects."));
5070
5071 for (const auto &cell : background_dof_handler.active_cell_iterators() |
5073 process_cell(cell, ls_vector, iso_level, vertices, cells);
5074 }
5075
5076 template <int dim, typename VectorType>
5077 void
5079 const DoFHandler<dim> &background_dof_handler,
5080 const VectorType &ls_vector,
5081 const double iso_level,
5082 std::vector<Point<dim>> &vertices) const
5083 {
5084 for (const auto &cell : background_dof_handler.active_cell_iterators() |
5086 process_cell(cell, ls_vector, iso_level, vertices);
5087
5088 delete_duplicated_vertices(vertices, 1e-10 /*tol*/);
5089 }
5090
5091
5092 template <int dim, typename VectorType>
5093 void
5095 const typename DoFHandler<dim>::active_cell_iterator &cell,
5096 const VectorType &ls_vector,
5097 const double iso_level,
5098 std::vector<Point<dim>> &vertices,
5099 std::vector<CellData<dim == 1 ? 1 : dim - 1>> &cells) const
5100 {
5102 dim > 1,
5103 ExcMessage(
5104 "Not implemented for dim==1. Use the alternative process_cell()-function "
5105 "not returning a vector of CellData objects."));
5106
5107 std::vector<value_type> ls_values;
5108
5109 fe_values.reinit(cell);
5110 ls_values.resize(fe_values.n_quadrature_points);
5111 fe_values.get_function_values(ls_vector, ls_values);
5112 process_cell(
5113 ls_values, fe_values.get_quadrature_points(), iso_level, vertices, cells);
5114 }
5115
5116 template <int dim, typename VectorType>
5117 void
5119 const typename DoFHandler<dim>::active_cell_iterator &cell,
5120 const VectorType &ls_vector,
5121 const double iso_level,
5122 std::vector<Point<dim>> &vertices) const
5123 {
5124 // This vector is just a placeholder to reuse the process_cell function.
5125 std::vector<CellData<dim == 1 ? 1 : dim - 1>> dummy_cells;
5126
5127 std::vector<value_type> ls_values;
5128
5129 fe_values.reinit(cell);
5130 ls_values.resize(fe_values.n_quadrature_points);
5131 fe_values.get_function_values(ls_vector, ls_values);
5132
5133 process_cell(ls_values,
5134 fe_values.get_quadrature_points(),
5135 iso_level,
5136 vertices,
5137 dummy_cells,
5138 false /*don't write back cell data*/);
5139 }
5140
5141
5142 template <int dim, typename VectorType>
5143 void
5145 std::vector<value_type> &ls_values,
5146 const std::vector<Point<dim>> &points,
5147 const double iso_level,
5148 std::vector<Point<dim>> &vertices,
5149 std::vector<CellData<dim == 1 ? 1 : dim - 1>> &cells,
5150 const bool write_back_cell_data) const
5151 {
5152 const unsigned p = n_subdivisions + 1;
5153
5154 if (dim == 1)
5155 {
5156 for (unsigned int i = 0; i < n_subdivisions; ++i)
5157 {
5158 std::vector<unsigned int> mask{i + 0, i + 1};
5159
5160 // check if a corner node is cut
5161 if (std::abs(iso_level - ls_values[mask[0]]) < tolerance)
5162 vertices.emplace_back(points[mask[0]]);
5163 else if (std::abs(iso_level - ls_values[mask[1]]) < tolerance)
5164 {
5165 if (i + 1 == n_subdivisions)
5166 vertices.emplace_back(points[mask[1]]);
5167 }
5168 // check if the edge is cut
5169 else if (((ls_values[mask[0]] > iso_level) &&
5170 (ls_values[mask[1]] < iso_level)) ||
5171 ((ls_values[mask[0]] < iso_level) &&
5172 (ls_values[mask[1]] > iso_level)))
5173 {
5174 // determine the interpolation weight (0<mu<1)
5175 const double mu = (iso_level - ls_values[mask[0]]) /
5176 (ls_values[mask[1]] - ls_values[mask[0]]);
5177
5178 // interpolate
5179 vertices.emplace_back(points[mask[0]] +
5180 mu * (points[mask[1]] - points[mask[0]]));
5181 }
5182 }
5183 }
5184 else if (dim == 2)
5185 {
5186 for (unsigned int j = 0; j < n_subdivisions; ++j)
5187 for (unsigned int i = 0; i < n_subdivisions; ++i)
5188 {
5189 std::vector<unsigned int> mask{p * (j + 0) + (i + 0),
5190 p * (j + 0) + (i + 1),
5191 p * (j + 1) + (i + 1),
5192 p * (j + 1) + (i + 0)};
5193
5194 process_sub_cell(ls_values,
5195 points,
5196 mask,
5197 iso_level,
5198 vertices,
5199 cells,
5200 write_back_cell_data);
5201 }
5202 }
5203 else if (dim == 3)
5204 {
5205 for (unsigned int k = 0; k < n_subdivisions; ++k)
5206 for (unsigned int j = 0; j < n_subdivisions; ++j)
5207 for (unsigned int i = 0; i < n_subdivisions; ++i)
5208 {
5209 std::vector<unsigned int> mask{
5210 p * p * (k + 0) + p * (j + 0) + (i + 0),
5211 p * p * (k + 0) + p * (j + 0) + (i + 1),
5212 p * p * (k + 0) + p * (j + 1) + (i + 1),
5213 p * p * (k + 0) + p * (j + 1) + (i + 0),
5214 p * p * (k + 1) + p * (j + 0) + (i + 0),
5215 p * p * (k + 1) + p * (j + 0) + (i + 1),
5216 p * p * (k + 1) + p * (j + 1) + (i + 1),
5217 p * p * (k + 1) + p * (j + 1) + (i + 0)};
5218
5219 process_sub_cell(ls_values,
5220 points,
5221 mask,
5222 iso_level,
5223 vertices,
5224 cells,
5225 write_back_cell_data);
5226 }
5227 }
5228 }
5229
5230
5231
5232 template <int dim, typename VectorType>
5233 void
5235 const std::vector<value_type> &ls_values,
5236 const std::vector<Point<2>> &points,
5237 const std::vector<unsigned int> &mask,
5238 const double iso_level,
5239 std::vector<Point<2>> &vertices,
5240 std::vector<CellData<1>> &cells,
5241 const bool write_back_cell_data) const
5242 {
5243 // set up dimension-dependent sizes and tables
5244 constexpr unsigned int n_vertices = 4;
5245 constexpr unsigned int n_sub_vertices = 2;
5246 constexpr unsigned int n_lines = 4;
5247 constexpr unsigned int n_configurations = Utilities::pow(2, n_vertices);
5248 constexpr unsigned int X = static_cast<unsigned int>(-1);
5249
5250 // table that indicates if an edge is cut (if the i-th bit is set the i-th
5251 // line is cut)
5252 constexpr std::array<unsigned int, n_configurations> cut_line_table = {
5253 {0b0000,
5254 0b0101,
5255 0b0110,
5256 0b0011,
5257 0b1010,
5258 0b0000,
5259 0b1100,
5260 0b1001,
5261 0b1001,
5262 0b1100,
5263 0b0000,
5264 0b1010,
5265 0b0011,
5266 0b0110,
5267 0b0101,
5268 0b0000}};
5269
5270 // list of the definition of the newly created lines (each line is defined
5271 // by two edges it cuts)
5272 constexpr ndarray<unsigned int, n_configurations, 5> new_line_table = {
5273 {{{X, X, X, X, X}},
5274 {{0, 2, X, X, X}},
5275 {{1, 2, X, X, X}},
5276 {{0, 1, X, X, X}},
5277 {{1, 3, X, X, X}},
5278 {{X, X, X, X, X}},
5279 {{2, 3, X, X, X}},
5280 {{0, 3, X, X, X}},
5281 {{0, 3, X, X, X}},
5282 {{2, 3, X, X, X}},
5283 {{X, X, X, X, X}},
5284 {{1, 3, X, X, X}},
5285 {{0, 1, X, X, X}},
5286 {{2, 1, X, X, X}},
5287 {{0, 2, X, X, X}},
5288 {{X, X, X, X, X}}}};
5289
5290 // vertices of each line
5291 constexpr ndarray<unsigned int, n_lines, 2> line_to_vertex_table = {
5292 {{{0, 3}}, {{1, 2}}, {{0, 1}}, {{3, 2}}}};
5293
5294 // run dimension-independent code
5296 n_vertices,
5297 n_sub_vertices,
5298 n_configurations,
5299 n_lines,
5300 5>(cut_line_table,
5301 new_line_table,
5302 line_to_vertex_table,
5303 ls_values,
5304 points,
5305 mask,
5306 iso_level,
5307 tolerance,
5308 vertices,
5309 cells,
5310 write_back_cell_data);
5311 }
5312
5313
5314
5315 template <int dim, typename VectorType>
5316 void
5318 const std::vector<value_type> &ls_values,
5319 const std::vector<Point<3>> &points,
5320 const std::vector<unsigned int> &mask,
5321 const double iso_level,
5322 std::vector<Point<3>> &vertices,
5323 std::vector<CellData<2>> &cells,
5324 const bool write_back_cell_data) const
5325 {
5326 // set up dimension-dependent sizes and tables
5327 constexpr unsigned int n_vertices = 8;
5328 constexpr unsigned int n_sub_vertices = 3;
5329 constexpr unsigned int n_lines = 12;
5330 constexpr unsigned int n_configurations = Utilities::pow(2, n_vertices);
5331 constexpr unsigned int X = static_cast<unsigned int>(-1);
5332
5333 // clang-format off
5334 // table that indicates if an edge is cut (if the i-th bit is set the i-th
5335 // line is cut)
5336 constexpr std::array<unsigned int, n_configurations> cut_line_table = {{
5337 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905,
5338 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99, 0x393, 0x29a,
5339 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93,
5340 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
5341 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9,
5342 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6,
5343 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f,
5344 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
5345 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, 0xdfc, 0xcf5,
5346 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a,
5347 0x256, 0x35f, 0x55, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53,
5348 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
5349 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9,
5350 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc, 0x1c5, 0x2cf, 0x3c6,
5351 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f,
5352 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
5353 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5,
5354 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a,
5355 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663,
5356 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
5357 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39,
5358 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636,
5359 0x13a, 0x33, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f,
5360 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
5361 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605,
5362 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0}};
5363 // clang-format on
5364
5365 // list of the definition of the newly created triangles (each triangles is
5366 // defined by two edges it cuts)
5367 constexpr ndarray<unsigned int, n_configurations, 16> new_line_table = {
5368 {{{X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5369 {{0, 8, 3, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5370 {{0, 1, 9, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5371 {{1, 8, 3, 9, 8, 1, X, X, X, X, X, X, X, X, X, X}},
5372 {{1, 2, 10, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5373 {{0, 8, 3, 1, 2, 10, X, X, X, X, X, X, X, X, X, X}},
5374 {{9, 2, 10, 0, 2, 9, X, X, X, X, X, X, X, X, X, X}},
5375 {{2, 8, 3, 2, 10, 8, 10, 9, 8, X, X, X, X, X, X, X}},
5376 {{3, 11, 2, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5377 {{0, 11, 2, 8, 11, 0, X, X, X, X, X, X, X, X, X, X}},
5378 {{1, 9, 0, 2, 3, 11, X, X, X, X, X, X, X, X, X, X}},
5379 {{1, 11, 2, 1, 9, 11, 9, 8, 11, X, X, X, X, X, X, X}},
5380 {{3, 10, 1, 11, 10, 3, X, X, X, X, X, X, X, X, X, X}},
5381 {{0, 10, 1, 0, 8, 10, 8, 11, 10, X, X, X, X, X, X, X}},
5382 {{3, 9, 0, 3, 11, 9, 11, 10, 9, X, X, X, X, X, X, X}},
5383 {{9, 8, 10, 10, 8, 11, X, X, X, X, X, X, X, X, X, X}},
5384 {{4, 7, 8, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5385 {{4, 3, 0, 7, 3, 4, X, X, X, X, X, X, X, X, X, X}},
5386 {{0, 1, 9, 8, 4, 7, X, X, X, X, X, X, X, X, X, X}},
5387 {{4, 1, 9, 4, 7, 1, 7, 3, 1, X, X, X, X, X, X, X}},
5388 {{1, 2, 10, 8, 4, 7, X, X, X, X, X, X, X, X, X, X}},
5389 {{3, 4, 7, 3, 0, 4, 1, 2, 10, X, X, X, X, X, X, X}},
5390 {{9, 2, 10, 9, 0, 2, 8, 4, 7, X, X, X, X, X, X, X}},
5391 {{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, X, X, X, X}},
5392 {{8, 4, 7, 3, 11, 2, X, X, X, X, X, X, X, X, X, X}},
5393 {{11, 4, 7, 11, 2, 4, 2, 0, 4, X, X, X, X, X, X, X}},
5394 {{9, 0, 1, 8, 4, 7, 2, 3, 11, X, X, X, X, X, X, X}},
5395 {{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, X, X, X, X}},
5396 {{3, 10, 1, 3, 11, 10, 7, 8, 4, X, X, X, X, X, X, X}},
5397 {{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, X, X, X, X}},
5398 {{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, X, X, X, X}},
5399 {{4, 7, 11, 4, 11, 9, 9, 11, 10, X, X, X, X, X, X, X}},
5400 {{9, 5, 4, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5401 {{9, 5, 4, 0, 8, 3, X, X, X, X, X, X, X, X, X, X}},
5402 {{0, 5, 4, 1, 5, 0, X, X, X, X, X, X, X, X, X, X}},
5403 {{8, 5, 4, 8, 3, 5, 3, 1, 5, X, X, X, X, X, X, X}},
5404 {{1, 2, 10, 9, 5, 4, X, X, X, X, X, X, X, X, X, X}},
5405 {{3, 0, 8, 1, 2, 10, 4, 9, 5, X, X, X, X, X, X, X}},
5406 {{5, 2, 10, 5, 4, 2, 4, 0, 2, X, X, X, X, X, X, X}},
5407 {{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, X, X, X, X}},
5408 {{9, 5, 4, 2, 3, 11, X, X, X, X, X, X, X, X, X, X}},
5409 {{0, 11, 2, 0, 8, 11, 4, 9, 5, X, X, X, X, X, X, X}},
5410 {{0, 5, 4, 0, 1, 5, 2, 3, 11, X, X, X, X, X, X, X}},
5411 {{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, X, X, X, X}},
5412 {{10, 3, 11, 10, 1, 3, 9, 5, 4, X, X, X, X, X, X, X}},
5413 {{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, X, X, X, X}},
5414 {{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, X, X, X, X}},
5415 {{5, 4, 8, 5, 8, 10, 10, 8, 11, X, X, X, X, X, X, X}},
5416 {{9, 7, 8, 5, 7, 9, X, X, X, X, X, X, X, X, X, X}},
5417 {{9, 3, 0, 9, 5, 3, 5, 7, 3, X, X, X, X, X, X, X}},
5418 {{0, 7, 8, 0, 1, 7, 1, 5, 7, X, X, X, X, X, X, X}},
5419 {{1, 5, 3, 3, 5, 7, X, X, X, X, X, X, X, X, X, X}},
5420 {{9, 7, 8, 9, 5, 7, 10, 1, 2, X, X, X, X, X, X, X}},
5421 {{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, X, X, X, X}},
5422 {{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, X, X, X, X}},
5423 {{2, 10, 5, 2, 5, 3, 3, 5, 7, X, X, X, X, X, X, X}},
5424 {{7, 9, 5, 7, 8, 9, 3, 11, 2, X, X, X, X, X, X, X}},
5425 {{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, X, X, X, X}},
5426 {{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, X, X, X, X}},
5427 {{11, 2, 1, 11, 1, 7, 7, 1, 5, X, X, X, X, X, X, X}},
5428 {{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, X, X, X, X}},
5429 {{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, X}},
5430 {{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, X}},
5431 {{11, 10, 5, 7, 11, 5, X, X, X, X, X, X, X, X, X, X}},
5432 {{10, 6, 5, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5433 {{0, 8, 3, 5, 10, 6, X, X, X, X, X, X, X, X, X, X}},
5434 {{9, 0, 1, 5, 10, 6, X, X, X, X, X, X, X, X, X, X}},
5435 {{1, 8, 3, 1, 9, 8, 5, 10, 6, X, X, X, X, X, X, X}},
5436 {{1, 6, 5, 2, 6, 1, X, X, X, X, X, X, X, X, X, X}},
5437 {{1, 6, 5, 1, 2, 6, 3, 0, 8, X, X, X, X, X, X, X}},
5438 {{9, 6, 5, 9, 0, 6, 0, 2, 6, X, X, X, X, X, X, X}},
5439 {{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, X, X, X, X}},
5440 {{2, 3, 11, 10, 6, 5, X, X, X, X, X, X, X, X, X, X}},
5441 {{11, 0, 8, 11, 2, 0, 10, 6, 5, X, X, X, X, X, X, X}},
5442 {{0, 1, 9, 2, 3, 11, 5, 10, 6, X, X, X, X, X, X, X}},
5443 {{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, X, X, X, X}},
5444 {{6, 3, 11, 6, 5, 3, 5, 1, 3, X, X, X, X, X, X, X}},
5445 {{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, X, X, X, X}},
5446 {{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, X, X, X, X}},
5447 {{6, 5, 9, 6, 9, 11, 11, 9, 8, X, X, X, X, X, X, X}},
5448 {{5, 10, 6, 4, 7, 8, X, X, X, X, X, X, X, X, X, X}},
5449 {{4, 3, 0, 4, 7, 3, 6, 5, 10, X, X, X, X, X, X, X}},
5450 {{1, 9, 0, 5, 10, 6, 8, 4, 7, X, X, X, X, X, X, X}},
5451 {{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, X, X, X, X}},
5452 {{6, 1, 2, 6, 5, 1, 4, 7, 8, X, X, X, X, X, X, X}},
5453 {{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, X, X, X, X}},
5454 {{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, X, X, X, X}},
5455 {{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, X}},
5456 {{3, 11, 2, 7, 8, 4, 10, 6, 5, X, X, X, X, X, X, X}},
5457 {{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, X, X, X, X}},
5458 {{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, X, X, X, X}},
5459 {{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, X}},
5460 {{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, X, X, X, X}},
5461 {{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, X}},
5462 {{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, X}},
5463 {{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, X, X, X, X}},
5464 {{10, 4, 9, 6, 4, 10, X, X, X, X, X, X, X, X, X, X}},
5465 {{4, 10, 6, 4, 9, 10, 0, 8, 3, X, X, X, X, X, X, X}},
5466 {{10, 0, 1, 10, 6, 0, 6, 4, 0, X, X, X, X, X, X, X}},
5467 {{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, X, X, X, X}},
5468 {{1, 4, 9, 1, 2, 4, 2, 6, 4, X, X, X, X, X, X, X}},
5469 {{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, X, X, X, X}},
5470 {{0, 2, 4, 4, 2, 6, X, X, X, X, X, X, X, X, X, X}},
5471 {{8, 3, 2, 8, 2, 4, 4, 2, 6, X, X, X, X, X, X, X}},
5472 {{10, 4, 9, 10, 6, 4, 11, 2, 3, X, X, X, X, X, X, X}},
5473 {{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, X, X, X, X}},
5474 {{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, X, X, X, X}},
5475 {{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, X}},
5476 {{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, X, X, X, X}},
5477 {{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, X}},
5478 {{3, 11, 6, 3, 6, 0, 0, 6, 4, X, X, X, X, X, X, X}},
5479 {{6, 4, 8, 11, 6, 8, X, X, X, X, X, X, X, X, X, X}},
5480 {{7, 10, 6, 7, 8, 10, 8, 9, 10, X, X, X, X, X, X, X}},
5481 {{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, X, X, X, X}},
5482 {{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, X, X, X, X}},
5483 {{10, 6, 7, 10, 7, 1, 1, 7, 3, X, X, X, X, X, X, X}},
5484 {{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, X, X, X, X}},
5485 {{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, X}},
5486 {{7, 8, 0, 7, 0, 6, 6, 0, 2, X, X, X, X, X, X, X}},
5487 {{7, 3, 2, 6, 7, 2, X, X, X, X, X, X, X, X, X, X}},
5488 {{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, X, X, X, X}},
5489 {{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, X}},
5490 {{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, X}},
5491 {{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, X, X, X, X}},
5492 {{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, X}},
5493 {{0, 9, 1, 11, 6, 7, X, X, X, X, X, X, X, X, X, X}},
5494 {{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, X, X, X, X}},
5495 {{7, 11, 6, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5496 {{7, 6, 11, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5497 {{3, 0, 8, 11, 7, 6, X, X, X, X, X, X, X, X, X, X}},
5498 {{0, 1, 9, 11, 7, 6, X, X, X, X, X, X, X, X, X, X}},
5499 {{8, 1, 9, 8, 3, 1, 11, 7, 6, X, X, X, X, X, X, X}},
5500 {{10, 1, 2, 6, 11, 7, X, X, X, X, X, X, X, X, X, X}},
5501 {{1, 2, 10, 3, 0, 8, 6, 11, 7, X, X, X, X, X, X, X}},
5502 {{2, 9, 0, 2, 10, 9, 6, 11, 7, X, X, X, X, X, X, X}},
5503 {{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, X, X, X, X}},
5504 {{7, 2, 3, 6, 2, 7, X, X, X, X, X, X, X, X, X, X}},
5505 {{7, 0, 8, 7, 6, 0, 6, 2, 0, X, X, X, X, X, X, X}},
5506 {{2, 7, 6, 2, 3, 7, 0, 1, 9, X, X, X, X, X, X, X}},
5507 {{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, X, X, X, X}},
5508 {{10, 7, 6, 10, 1, 7, 1, 3, 7, X, X, X, X, X, X, X}},
5509 {{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, X, X, X, X}},
5510 {{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, X, X, X, X}},
5511 {{7, 6, 10, 7, 10, 8, 8, 10, 9, X, X, X, X, X, X, X}},
5512 {{6, 8, 4, 11, 8, 6, X, X, X, X, X, X, X, X, X, X}},
5513 {{3, 6, 11, 3, 0, 6, 0, 4, 6, X, X, X, X, X, X, X}},
5514 {{8, 6, 11, 8, 4, 6, 9, 0, 1, X, X, X, X, X, X, X}},
5515 {{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, X, X, X, X}},
5516 {{6, 8, 4, 6, 11, 8, 2, 10, 1, X, X, X, X, X, X, X}},
5517 {{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, X, X, X, X}},
5518 {{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, X, X, X, X}},
5519 {{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, X}},
5520 {{8, 2, 3, 8, 4, 2, 4, 6, 2, X, X, X, X, X, X, X}},
5521 {{0, 4, 2, 4, 6, 2, X, X, X, X, X, X, X, X, X, X}},
5522 {{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, X, X, X, X}},
5523 {{1, 9, 4, 1, 4, 2, 2, 4, 6, X, X, X, X, X, X, X}},
5524 {{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, X, X, X, X}},
5525 {{10, 1, 0, 10, 0, 6, 6, 0, 4, X, X, X, X, X, X, X}},
5526 {{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, X}},
5527 {{10, 9, 4, 6, 10, 4, X, X, X, X, X, X, X, X, X, X}},
5528 {{4, 9, 5, 7, 6, 11, X, X, X, X, X, X, X, X, X, X}},
5529 {{0, 8, 3, 4, 9, 5, 11, 7, 6, X, X, X, X, X, X, X}},
5530 {{5, 0, 1, 5, 4, 0, 7, 6, 11, X, X, X, X, X, X, X}},
5531 {{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, X, X, X, X}},
5532 {{9, 5, 4, 10, 1, 2, 7, 6, 11, X, X, X, X, X, X, X}},
5533 {{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, X, X, X, X}},
5534 {{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, X, X, X, X}},
5535 {{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, X}},
5536 {{7, 2, 3, 7, 6, 2, 5, 4, 9, X, X, X, X, X, X, X}},
5537 {{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, X, X, X, X}},
5538 {{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, X, X, X, X}},
5539 {{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, X}},
5540 {{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, X, X, X, X}},
5541 {{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, X}},
5542 {{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, X}},
5543 {{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, X, X, X, X}},
5544 {{6, 9, 5, 6, 11, 9, 11, 8, 9, X, X, X, X, X, X, X}},
5545 {{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, X, X, X, X}},
5546 {{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, X, X, X, X}},
5547 {{6, 11, 3, 6, 3, 5, 5, 3, 1, X, X, X, X, X, X, X}},
5548 {{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, X, X, X, X}},
5549 {{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, X}},
5550 {{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, X}},
5551 {{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, X, X, X, X}},
5552 {{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, X, X, X, X}},
5553 {{9, 5, 6, 9, 6, 0, 0, 6, 2, X, X, X, X, X, X, X}},
5554 {{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, X}},
5555 {{1, 5, 6, 2, 1, 6, X, X, X, X, X, X, X, X, X, X}},
5556 {{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, X}},
5557 {{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, X, X, X, X}},
5558 {{0, 3, 8, 5, 6, 10, X, X, X, X, X, X, X, X, X, X}},
5559 {{10, 5, 6, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5560 {{11, 5, 10, 7, 5, 11, X, X, X, X, X, X, X, X, X, X}},
5561 {{11, 5, 10, 11, 7, 5, 8, 3, 0, X, X, X, X, X, X, X}},
5562 {{5, 11, 7, 5, 10, 11, 1, 9, 0, X, X, X, X, X, X, X}},
5563 {{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, X, X, X, X}},
5564 {{11, 1, 2, 11, 7, 1, 7, 5, 1, X, X, X, X, X, X, X}},
5565 {{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, X, X, X, X}},
5566 {{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, X, X, X, X}},
5567 {{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, X}},
5568 {{2, 5, 10, 2, 3, 5, 3, 7, 5, X, X, X, X, X, X, X}},
5569 {{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, X, X, X, X}},
5570 {{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, X, X, X, X}},
5571 {{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, X}},
5572 {{1, 3, 5, 3, 7, 5, X, X, X, X, X, X, X, X, X, X}},
5573 {{0, 8, 7, 0, 7, 1, 1, 7, 5, X, X, X, X, X, X, X}},
5574 {{9, 0, 3, 9, 3, 5, 5, 3, 7, X, X, X, X, X, X, X}},
5575 {{9, 8, 7, 5, 9, 7, X, X, X, X, X, X, X, X, X, X}},
5576 {{5, 8, 4, 5, 10, 8, 10, 11, 8, X, X, X, X, X, X, X}},
5577 {{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, X, X, X, X}},
5578 {{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, X, X, X, X}},
5579 {{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, X}},
5580 {{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, X, X, X, X}},
5581 {{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, X}},
5582 {{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, X}},
5583 {{9, 4, 5, 2, 11, 3, X, X, X, X, X, X, X, X, X, X}},
5584 {{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, X, X, X, X}},
5585 {{5, 10, 2, 5, 2, 4, 4, 2, 0, X, X, X, X, X, X, X}},
5586 {{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, X}},
5587 {{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, X, X, X, X}},
5588 {{8, 4, 5, 8, 5, 3, 3, 5, 1, X, X, X, X, X, X, X}},
5589 {{0, 4, 5, 1, 0, 5, X, X, X, X, X, X, X, X, X, X}},
5590 {{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, X, X, X, X}},
5591 {{9, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5592 {{4, 11, 7, 4, 9, 11, 9, 10, 11, X, X, X, X, X, X, X}},
5593 {{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, X, X, X, X}},
5594 {{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, X, X, X, X}},
5595 {{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, X}},
5596 {{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, X, X, X, X}},
5597 {{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, X}},
5598 {{11, 7, 4, 11, 4, 2, 2, 4, 0, X, X, X, X, X, X, X}},
5599 {{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, X, X, X, X}},
5600 {{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, X, X, X, X}},
5601 {{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, X}},
5602 {{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, X}},
5603 {{1, 10, 2, 8, 7, 4, X, X, X, X, X, X, X, X, X, X}},
5604 {{4, 9, 1, 4, 1, 7, 7, 1, 3, X, X, X, X, X, X, X}},
5605 {{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, X, X, X, X}},
5606 {{4, 0, 3, 7, 4, 3, X, X, X, X, X, X, X, X, X, X}},
5607 {{4, 8, 7, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5608 {{9, 10, 8, 10, 11, 8, X, X, X, X, X, X, X, X, X, X}},
5609 {{3, 0, 9, 3, 9, 11, 11, 9, 10, X, X, X, X, X, X, X}},
5610 {{0, 1, 10, 0, 10, 8, 8, 10, 11, X, X, X, X, X, X, X}},
5611 {{3, 1, 10, 11, 3, 10, X, X, X, X, X, X, X, X, X, X}},
5612 {{1, 2, 11, 1, 11, 9, 9, 11, 8, X, X, X, X, X, X, X}},
5613 {{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, X, X, X, X}},
5614 {{0, 2, 11, 8, 0, 11, X, X, X, X, X, X, X, X, X, X}},
5615 {{3, 2, 11, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5616 {{2, 3, 8, 2, 8, 10, 10, 8, 9, X, X, X, X, X, X, X}},
5617 {{9, 10, 2, 0, 9, 2, X, X, X, X, X, X, X, X, X, X}},
5618 {{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, X, X, X, X}},
5619 {{1, 10, 2, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5620 {{1, 3, 8, 9, 1, 8, X, X, X, X, X, X, X, X, X, X}},
5621 {{0, 9, 1, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5622 {{0, 3, 8, X, X, X, X, X, X, X, X, X, X, X, X, X}},
5623 {{X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X}}}};
5624
5625 // vertices of each line
5626 static constexpr ndarray<unsigned int, n_lines, 2> line_to_vertex_table = {
5627 {{{0, 1}},
5628 {{1, 2}},
5629 {{2, 3}},
5630 {{3, 0}},
5631 {{4, 5}},
5632 {{5, 6}},
5633 {{6, 7}},
5634 {{7, 4}},
5635 {{0, 4}},
5636 {{1, 5}},
5637 {{2, 6}},
5638 {{3, 7}}}};
5639
5640 // run dimension-independent code
5642 n_vertices,
5643 n_sub_vertices,
5644 n_configurations,
5645 n_lines,
5646 16>(cut_line_table,
5647 new_line_table,
5648 line_to_vertex_table,
5649 ls_values,
5650 points,
5651 mask,
5652 iso_level,
5653 tolerance,
5654 vertices,
5655 cells,
5656 write_back_cell_data);
5657 }
5658
5659} /* namespace GridTools */
5660
5661
5662// explicit instantiations
5663#include "grid/grid_tools.inst"
5664
void distribute(VectorType &vec) const
std::pair< std::vector< std::pair< int, int > >, std::vector< int > > query(const QueryType &queries)
DistributedTree(const MPI_Comm comm, const std::vector< BoundingBox< dim, Number > > &bounding_boxes)
BoundingBox< spacedim, Number > create_extended_relative(const Number relative_amount) const
BoundingBox< spacedim, Number > create_extended(const Number amount) const
void distribute_dofs(const FiniteElement< dim, spacedim > &fe)
types::global_dof_index n_dofs() const
Definition fe_q.h:552
const std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > & get_vertex_to_cell_map() const
const std::vector< std::vector< Tensor< 1, spacedim > > > & get_vertex_to_cell_centers_directions() const
const RTree< std::pair< BoundingBox< spacedim >, typename Triangulation< dim, spacedim >::active_cell_iterator > > & get_locally_owned_cell_bounding_boxes_rtree() const
const Mapping< dim, spacedim > & get_mapping() const
const Triangulation< dim, spacedim > & get_triangulation() const
const RTree< std::pair< Point< spacedim >, unsigned int > > & get_used_vertices_rtree() const
const RTree< std::pair< BoundingBox< spacedim >, typename Triangulation< dim, spacedim >::active_cell_iterator > > & get_cell_bounding_boxes_rtree() const
static Quadrature< dim > create_quadrature_rule(const unsigned int n_subdivisions)
void process_cell(const typename DoFHandler< dim >::active_cell_iterator &cell, const VectorType &ls_vector, const double iso_level, std::vector< Point< dim > > &vertices, std::vector< CellData< dim==1 ? 1 :dim - 1 > > &cells) const
void process_sub_cell(const std::vector< value_type > &, const std::vector< Point< 1 > > &, const std::vector< unsigned int > &, const double, std::vector< Point< 1 > > &, std::vector< CellData< 1 > > &, const bool) const
void process(const DoFHandler< dim > &background_dof_handler, const VectorType &ls_vector, const double iso_level, std::vector< Point< dim > > &vertices, std::vector< CellData< dim==1 ? 1 :dim - 1 > > &cells) const
const Tensor< 2, 2, double > rotation_matrix
Point< 2 > operator()(const Point< 2 > &p) const
Rotate2d(const double angle)
Point< 3 > operator()(const Point< 3 > &p) const
Rotate3d(const Tensor< 1, 3, double > &axis, const double angle)
const Tensor< 2, 3, double > rotation_matrix
Scale(const double factor)
Point< spacedim > operator()(const Point< spacedim > p) const
Shift(const Tensor< 1, spacedim > &shift)
Point< spacedim > operator()(const Point< spacedim > p) const
const Tensor< 1, spacedim > shift
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const =0
Abstract base class for mapping classes.
Definition mapping.h:318
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) const =0
virtual boost::container::small_vector< Point< spacedim >, ReferenceCells::max_n_vertices< dim >() > get_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
Definition point.h:111
constexpr numbers::NumberTraits< Number >::real_type distance_square(const Point< dim, Number > &p) const
numbers::NumberTraits< Number >::real_type distance(const Point< dim, Number > &p) const
constexpr numbers::NumberTraits< Number >::real_type square() const
void initialize(const MatrixType &A, const AdditionalData &parameters=AdditionalData())
Quadrature< spacedim > compute_affine_transformation(const std::array< Point< spacedim >, dim+1 > &vertices) const
const Point< dim > & point(const unsigned int i) const
unsigned int size() const
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
size_type n() const
size_type n_rows() const
size_type n_cols() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
numbers::NumberTraits< Number >::real_type norm() const
IteratorState::IteratorStates state() const
virtual types::global_cell_index n_global_active_cells() const
unsigned int n_quads() const
void load_user_indices(const std::vector< unsigned int > &v)
virtual void clear()
bool all_reference_cells_are_hyper_cube() const
void clear_user_data()
face_iterator end_face() const
cell_iterator create_cell_iterator(const CellId &cell_id) const
cell_iterator begin(const unsigned int level=0) const
virtual MPI_Comm get_mpi_communicator() const
unsigned int n_lines() const
unsigned int n_raw_faces() const
virtual void create_triangulation(const std::vector< Point< spacedim > > &vertices, const std::vector< CellData< dim > > &cells, const SubCellData &subcelldata)
unsigned int n_active_cells() const
void refine_global(const unsigned int times=1)
const std::vector< Point< spacedim > > & get_vertices() const
unsigned int n_levels() const
cell_iterator end() const
virtual bool has_hanging_nodes() const
bool vertex_used(const unsigned int index) const
virtual void execute_coarsening_and_refinement()
unsigned int n_cells() const
const std::vector< bool > & get_used_vertices() const
Triangulation< dim, spacedim > & get_triangulation()
Signals signals
Definition tria.h:2588
unsigned int n_vertices() const
void save_user_indices(std::vector< unsigned int > &v) 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
virtual std::vector< types::boundary_id > get_boundary_ids() const
active_face_iterator begin_active_face() const
active_cell_iterator begin_active(const unsigned int level=0) const
virtual MPI_Comm get_mpi_communicator() const override
Definition tria_base.cc:158
const ::internal::p4est::types< dim >::forest * get_p4est() const
Definition tria.cc:2221
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:249
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
const unsigned int v0
const unsigned int v1
IteratorRange< active_cell_iterator > active_cell_iterators() const
IteratorRange< active_cell_iterator > active_cell_iterators() const
IteratorRange< cell_iterator > cell_iterators_on_level(const unsigned int level) const
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcNeedsMPI()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNeedsCGAL()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcScalingFactorNotPositive(double arg1)
#define AssertThrow(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
typename IteratorSelector::line_iterator line_iterator
Definition tria.h:1708
LinearOperator< Range, Domain, Payload > linear_operator(const OperatorExemplar &, const Matrix &)
PackagedOperation< Range > constrained_right_hand_side(const AffineConstraints< typename Range::value_type > &constraints, const LinearOperator< Range, Domain, Payload > &linop, const Range &right_hand_side)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
LinearOperator< Range, Domain, Payload > constrained_linear_operator(const AffineConstraints< typename Range::value_type > &constraints, const LinearOperator< Range, Domain, Payload > &linop)
@ update_values
Shape function values.
@ update_quadrature_points
Transformed quadrature points.
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
void copy_boundary_to_manifold_id(Triangulation< dim, spacedim > &tria, const bool reset_boundary_ids=false)
void copy_material_to_manifold_id(Triangulation< dim, spacedim > &tria, const bool compute_face_ids=false)
void map_boundary_to_manifold_ids(const std::vector< types::boundary_id > &src_boundary_ids, const std::vector< types::manifold_id > &dst_manifold_ids, Triangulation< dim, spacedim > &tria, const std::vector< types::boundary_id > &reset_boundary_ids={})
virtual std::vector< types::manifold_id > get_manifold_ids() const
void set_manifold(const types::manifold_id number, const Manifold< dim, spacedim > &manifold_object)
void assign_co_dimensional_manifold_indicators(Triangulation< dim, spacedim > &tria, const std::function< types::manifold_id(const std::set< types::manifold_id > &)> &disambiguation_function=[](const std::set< types::manifold_id > &manifold_ids) { if(manifold_ids.size()==1) return *manifold_ids.begin();else return numbers::flat_manifold_id;}, bool overwrite_only_flat_manifold_ids=true)
void consistently_order_cells(std::vector< CellData< dim > > &cells)
Task< RT > new_task(const std::function< RT()> &function)
const unsigned int my_rank
Definition mpi.cc:917
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
const MPI_Comm comm
Definition mpi.cc:912
const unsigned int n_procs
Definition mpi.cc:923
std::tuple< BoundingBox< MeshType::space_dimension >, bool > compute_cell_predicate_bounding_box(const typename MeshType::cell_iterator &parent_cell, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate)
bool fix_up_object(const Iterator &object)
double objective_function(const Iterator &object, const Point< spacedim > &object_mid_point)
void fix_up_faces(const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, std::integral_constant< int, dim >, std::integral_constant< int, spacedim >)
Point< Iterator::AccessorType::space_dimension > get_face_midpoint(const Iterator &object, const unsigned int f, std::integral_constant< int, 1 >)
double minimal_diameter(const Iterator &object)
void laplace_solve(const SparseMatrix< double > &S, const AffineConstraints< double > &constraints, Vector< double > &u)
std::tuple< std::vector< unsigned int >, std::vector< unsigned int >, std::vector< unsigned int > > guess_owners_of_entities(const MPI_Comm comm, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const std::vector< T > &entities, const double tolerance)
DistributedComputePointLocationsInternal< dim, spacedim > distributed_compute_point_locations(const GridTools::Cache< dim, spacedim > &cache, const std::vector< Point< spacedim > > &points, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const std::vector< bool > &marked_vertices, const double tolerance, const bool perform_handshake, const bool enforce_unique_mapping=false)
std::vector< std::pair< typename Triangulation< dim, spacedim >::active_cell_iterator, Point< dim > > > find_all_locally_owned_active_cells_around_point(const Cache< dim, spacedim > &cache, const Point< spacedim > &point, typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint, const std::vector< bool > &marked_vertices, const double tolerance, const bool enforce_unique_mapping)
void process_sub_cell(const std::array< unsigned int, n_configurations > &cut_line_table, const ndarray< unsigned int, n_configurations, n_cols > &new_line_table, const ndarray< unsigned int, n_lines, 2 > &line_to_vertex_table, const std::vector< value_type > &ls_values, const std::vector< Point< dim > > &points, const std::vector< unsigned int > &mask, const double iso_level, const double tolerance, std::vector< Point< dim > > &vertices, std::vector< CellData< dim==1 ? 1 :dim - 1 > > &cells, const bool write_back_cell_data)
void set_subdomain_id_in_zorder_recursively(IT cell, unsigned int &current_proc_idx, unsigned int &current_cell_idx, const unsigned int n_active_cells, const unsigned int n_partitions)
bool compare_point_association(const unsigned int a, const unsigned int b, const Tensor< 1, spacedim > &point_direction, const std::vector< Tensor< 1, spacedim > > &center_directions)
DistributedComputeIntersectionLocationsInternal< structdim, spacedim > distributed_compute_intersection_locations(const Cache< dim, spacedim > &cache, const std::vector< std::vector< Point< spacedim > > > &intersection_requests, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const std::vector< bool > &marked_vertices, const double tolerance)
void get_face_connectivity_of_cells(const Triangulation< dim, spacedim > &triangulation, DynamicSparsityPattern &connectivity)
void delete_unused_vertices(std::vector< Point< spacedim > > &vertices, std::vector< CellData< dim > > &cells, SubCellData &subcelldata)
std::vector< BoundingBox< MeshType::space_dimension > > compute_mesh_predicate_bounding_box(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate, const unsigned int refinement_level=0, const bool allow_merge=false, const unsigned int max_boxes=numbers::invalid_unsigned_int)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
RTree< std::pair< BoundingBox< spacedim >, unsigned int > > build_global_description_tree(const std::vector< BoundingBox< spacedim > > &local_description, const MPI_Comm mpi_communicator)
void partition_triangulation_zorder(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const bool group_siblings=true)
void rotate(const double angle, Triangulation< dim, spacedim > &triangulation)
return_type compute_point_locations(const Cache< dim, spacedim > &cache, const std::vector< Point< spacedim > > &points, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint=typename Triangulation< dim, spacedim >::active_cell_iterator())
unsigned int find_closest_vertex(const std::map< unsigned int, Point< spacedim > > &vertices, const Point< spacedim > &p)
void transform(const Transformation &transformation, Triangulation< dim, spacedim > &triangulation)
std::pair< typename MeshType< dim, spacedim >::active_cell_iterator, Point< dim > > find_active_cell_around_point(const Mapping< dim, spacedim > &mapping, const MeshType< dim, spacedim > &mesh, const Point< spacedim > &p, const std::vector< bool > &marked_vertices={}, const double tolerance=1.e-10)
std::vector< bool > get_locally_owned_vertices(const Triangulation< dim, spacedim > &triangulation)
std::vector< types::global_vertex_index > parallel_to_serial_vertex_indices(const Triangulation< dim, spacedim > &serial_tria, const Triangulation< dim, spacedim > &parallel_tria)
void regularize_corner_cells(Triangulation< dim, spacedim > &tria, const double limit_angle_fraction=.75)
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
std::map< unsigned int, types::global_vertex_index > compute_local_to_global_vertex_index_map(const Triangulation< dim, spacedim > &triangulation)
Point< Iterator::AccessorType::space_dimension > project_to_object(const Iterator &object, const Point< Iterator::AccessorType::space_dimension > &trial_point)
void laplace_transform(const std::map< unsigned int, Point< dim > > &new_points, Triangulation< dim > &tria, const Function< dim, double > *coefficient=nullptr, const bool solve_for_absolute_positions=false)
void partition_multigrid_levels(Triangulation< dim, spacedim > &triangulation)
void delete_duplicated_vertices(std::vector< Point< spacedim > > &all_vertices, std::vector< CellData< dim > > &cells, SubCellData &subcelldata, std::vector< unsigned int > &considered_vertices, const double tol=1e-12)
unsigned int find_closest_vertex_of_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell, const Point< spacedim > &position, const Mapping< dim, spacedim > &mapping=(ReferenceCells::get_hypercube< dim >() .template get_default_linear_mapping< spacedim >()))
std::map< unsigned int, std::set<::types::subdomain_id > > compute_vertices_with_ghost_neighbors(const Triangulation< dim, spacedim > &tria)
void collect_coinciding_vertices(const Triangulation< dim, spacedim > &tria, std::map< unsigned int, std::vector< unsigned int > > &coinciding_vertex_groups, std::map< unsigned int, unsigned int > &vertex_to_coinciding_vertex_group)
unsigned int count_cells_with_subdomain_association(const Triangulation< dim, spacedim > &triangulation, const types::subdomain_id subdomain)
return_type guess_point_owner(const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const std::vector< Point< spacedim > > &points)
void partition_triangulation(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const SparsityTools::Partitioner partitioner=SparsityTools::Partitioner::metis)
std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > vertex_to_cell_map(const Triangulation< dim, spacedim > &triangulation)
return_type compute_point_locations_try_all(const Cache< dim, spacedim > &cache, const std::vector< Point< spacedim > > &points, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint=typename Triangulation< dim, spacedim >::active_cell_iterator())
std::vector< types::subdomain_id > get_subdomain_association(const Triangulation< dim, spacedim > &triangulation, const std::vector< CellId > &cell_ids)
void distort_random(const double factor, Triangulation< dim, spacedim > &triangulation, const bool keep_boundary=true, const unsigned int seed=boost::random::mt19937::default_seed)
std::vector< std::vector< Tensor< 1, spacedim > > > vertex_to_cell_centers_directions(const Triangulation< dim, spacedim > &mesh, const std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > &vertex_to_cells)
std::vector< std::pair< typename MeshType< dim, spacedim >::active_cell_iterator, Point< dim > > > find_all_active_cells_around_point(const Mapping< dim, spacedim > &mapping, const MeshType< dim, spacedim > &mesh, const Point< spacedim > &p, const double tolerance, const std::pair< typename MeshType< dim, spacedim >::active_cell_iterator, Point< dim > > &first_cell, const std::vector< std::set< typename MeshType< dim, spacedim >::active_cell_iterator > > *vertex_to_cells=nullptr)
double diameter(const Triangulation< dim, spacedim > &tria)
void get_vertex_connectivity_of_cells_on_level(const Triangulation< dim, spacedim > &triangulation, const unsigned int level, DynamicSparsityPattern &connectivity)
std::vector< std::vector< BoundingBox< spacedim > > > exchange_local_bounding_boxes(const std::vector< BoundingBox< spacedim > > &local_bboxes, const MPI_Comm mpi_communicator)
std::map< unsigned int, Point< spacedim > > extract_used_vertices(const Triangulation< dim, spacedim > &container, const Mapping< dim, spacedim > &mapping=(ReferenceCells::get_hypercube< dim >() .template get_default_linear_mapping< spacedim >()))
return_type distributed_compute_point_locations(const GridTools::Cache< dim, spacedim > &cache, const std::vector< Point< spacedim > > &local_points, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const double tolerance=1e-10, const std::vector< bool > &marked_vertices={}, const bool enforce_unique_mapping=true)
@ valid
Iterator points to a valid object.
void create_laplace_matrix(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Quadrature< dim > &q, MatrixType &matrix, const Function< spacedim, typename MatrixType::value_type > *const a=nullptr, const AffineConstraints< typename MatrixType::value_type > &constraints=AffineConstraints< typename MatrixType::value_type >())
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices, const Partitioner partitioner=Partitioner::metis)
void reorder_hierarchical(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices)
@ grid_tools_compute_local_to_global_vertex_index_map2
GridTools::compute_local_to_global_vertex_index_map second tag.
Definition mpi_tags.h:105
@ grid_tools_compute_local_to_global_vertex_index_map
GridTools::compute_local_to_global_vertex_index_map.
Definition mpi_tags.h:103
T sum(const T &t, const MPI_Comm mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
T max(const T &t, const MPI_Comm mpi_communicator)
std::vector< T > all_gather(const MPI_Comm comm, const T &object_to_send)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:118
std::size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition utilities.h:1352
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1670
constexpr double PI
Definition numbers.h:240
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::manifold_id flat_manifold_id
Definition types.h:332
constexpr types::subdomain_id artificial_subdomain_id
Definition types.h:406
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 > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
inline ::VectorizedArray< Number, width > acos(const ::VectorizedArray< Number, width > &x)
std::uint64_t global_vertex_index
Definition types.h:55
unsigned int subdomain_id
Definition types.h:50
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray
Definition ndarray.h:105
boost::geometry::index::rtree< LeafType, IndexType, IndexableGetter > RTree
Definition rtree.h:159
RTree< typename LeafTypeIterator::value_type, IndexType, IndexableGetter > pack_rtree(const LeafTypeIterator &begin, const LeafTypeIterator &end)
types::manifold_id manifold_id
Definition cell_data.h:125
std_cxx26::inplace_vector< unsigned int, ReferenceCells::max_n_vertices< structdim >()> vertices
Definition cell_data.h:84
types::material_id material_id
Definition cell_data.h:103
types::boundary_id boundary_id
Definition cell_data.h:114
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices()
static void alternating_form_at_vertices(const Point< spacedim >(&vertices)[vertices_per_cell], Tensor< spacedim - dim, spacedim >(&forms)[vertices_per_cell])
std::map< unsigned int, std::vector< unsigned int > > communicate_indices(const std::vector< std::tuple< unsigned int, unsigned int, unsigned int > > &point_recv_components, const MPI_Comm comm) const
GridTools::internal::DistributedComputePointLocationsInternal< dim, spacedim > convert_to_distributed_compute_point_locations_internal(const unsigned int n_points_1D, const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping, std::vector< Quadrature< spacedim > > *mapped_quadratures_recv_comp=nullptr, const bool consistent_numbering_of_sender_and_receiver=false) const
std::vector< std::tuple< std::pair< int, int >, unsigned int, unsigned int, IntersectionType > > send_components
Definition grid_tools.h:849
std::vector< std::tuple< unsigned int, unsigned int, IntersectionType > > recv_components
Definition grid_tools.h:860
std::vector< std::tuple< unsigned int, unsigned int, unsigned int > > recv_components
Definition grid_tools.h:785
std::vector< std::tuple< std::pair< int, int >, unsigned int, unsigned int, Point< dim >, Point< spacedim >, unsigned int > > send_components
Definition grid_tools.h:760
std::vector< CellData< 2 > > boundary_quads
Definition cell_data.h:247
std::vector< CellData< 1 > > boundary_lines
Definition cell_data.h:231
boost::signals2::signal< unsigned int(const cell_iterator &, const ::CellStatus), CellWeightSum< unsigned int > > weight
Definition tria.h:2501
boost::signals2::signal< void()> pre_partition
Definition tria.h:2394