deal.II version GIT relicensing-7058-gb35ee29762 2026-11-11 09:30: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_dof_handlers.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) 2018 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
14#include <deal.II/base/point.h>
15#include <deal.II/base/tensor.h>
16#include <deal.II/base/types.h>
17
21
24
26
29#include <deal.II/grid/tria.h>
32
34
36
37#include <algorithm>
38#include <array>
39#include <cmath>
40#include <limits>
41#include <list>
42#include <map>
43#include <numeric>
44#include <optional>
45#include <set>
46#include <vector>
47
48
50
51namespace GridTools
52{
53 template <int dim, template <int, int> class MeshType, int spacedim>
55 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
56 unsigned int find_closest_vertex(const MeshType<dim, spacedim> &mesh,
57 const Point<spacedim> &p,
58 const std::vector<bool> &marked_vertices)
59 {
60 // first get the underlying
61 // triangulation from the
62 // mesh and determine vertices
63 // and used vertices
65
66 const std::vector<Point<spacedim>> &vertices = tria.get_vertices();
67
68 Assert(tria.get_vertices().size() == marked_vertices.size() ||
69 marked_vertices.empty(),
71 marked_vertices.size()));
72
73 // If p is an element of marked_vertices,
74 // and q is that of used_Vertices,
75 // the vector marked_vertices does NOT
76 // contain unused vertices if p implies q.
77 // I.e., if p is true q must be true
78 // (if p is false, q could be false or true).
79 // p implies q logic is encapsulated in ~p|q.
80 Assert(
81 marked_vertices.empty() ||
82 std::equal(marked_vertices.begin(),
83 marked_vertices.end(),
84 tria.get_used_vertices().begin(),
85 [](bool p, bool q) { return !p || q; }),
87 "marked_vertices should be a subset of used vertices in the triangulation "
88 "but marked_vertices contains one or more vertices that are not used vertices!"));
89
90 // In addition, if a vector bools
91 // is specified (marked_vertices)
92 // marking all the vertices which
93 // could be the potentially closest
94 // vertex to the point, use it instead
95 // of used vertices
96 const std::vector<bool> &used =
97 (marked_vertices.empty()) ? tria.get_used_vertices() : marked_vertices;
98
99 // At the beginning, the first
100 // used vertex is the closest one
101 std::vector<bool>::const_iterator first =
102 std::find(used.begin(), used.end(), true);
103
104 // Assert that at least one vertex
105 // is actually used
106 Assert(first != used.end(), ExcInternalError());
107
108 unsigned int best_vertex = std::distance(used.begin(), first);
109 double best_dist = (p - vertices[best_vertex]).norm_square();
110
111 // For all remaining vertices, test
112 // whether they are any closer
113 for (unsigned int j = best_vertex + 1; j < vertices.size(); ++j)
114 if (used[j])
115 {
116 double dist = (p - vertices[j]).norm_square();
117 if (dist < best_dist)
118 {
119 best_vertex = j;
120 best_dist = dist;
121 }
122 }
123
124 return best_vertex;
125 }
126
127
128
129 template <int dim, template <int, int> class MeshType, int spacedim>
131 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
132 unsigned int find_closest_vertex(const Mapping<dim, spacedim> &mapping,
133 const MeshType<dim, spacedim> &mesh,
134 const Point<spacedim> &p,
135 const std::vector<bool> &marked_vertices)
136 {
137 // Take a shortcut in the simple case.
138 if (mapping.preserves_vertex_locations() == true)
139 return find_closest_vertex(mesh, p, marked_vertices);
140
141 // first get the underlying
142 // triangulation from the
143 // mesh and determine vertices
144 // and used vertices
146
147 auto vertices = extract_used_vertices(tria, mapping);
148
149 Assert(tria.get_vertices().size() == marked_vertices.size() ||
150 marked_vertices.empty(),
152 marked_vertices.size()));
153
154 // If p is an element of marked_vertices,
155 // and q is that of used_Vertices,
156 // the vector marked_vertices does NOT
157 // contain unused vertices if p implies q.
158 // I.e., if p is true q must be true
159 // (if p is false, q could be false or true).
160 // p implies q logic is encapsulated in ~p|q.
161 Assert(
162 marked_vertices.empty() ||
163 std::equal(marked_vertices.begin(),
164 marked_vertices.end(),
165 tria.get_used_vertices().begin(),
166 [](bool p, bool q) { return !p || q; }),
168 "marked_vertices should be a subset of used vertices in the triangulation "
169 "but marked_vertices contains one or more vertices that are not used vertices!"));
170
171 // Remove from the map unwanted elements.
172 if (marked_vertices.size())
173 for (auto it = vertices.begin(); it != vertices.end();)
174 {
175 if (marked_vertices[it->first] == false)
176 {
177 vertices.erase(it++);
178 }
179 else
180 {
181 ++it;
182 }
183 }
184
185 return find_closest_vertex(vertices, p);
186 }
187
188
189
190 template <typename MeshType>
192#ifndef _MSC_VER
193 std::vector<typename MeshType::active_cell_iterator>
194#else
195 std::vector<
196 typename ::internal::ActiveCellIterator<MeshType::dimension,
197 MeshType::space_dimension,
198 MeshType>::type>
199#endif
200 find_cells_adjacent_to_vertex(const MeshType &mesh,
201 const unsigned int vertex)
202 {
203 const int dim = MeshType::dimension;
204 const int spacedim = MeshType::space_dimension;
205
206 // make sure that the given vertex is
207 // an active vertex of the underlying
208 // triangulation
209 AssertIndexRange(vertex, mesh.get_triangulation().n_vertices());
210 Assert(mesh.get_triangulation().get_used_vertices()[vertex],
211 ExcVertexNotUsed(vertex));
212
213 // use a set instead of a vector
214 // to ensure that cells are inserted only
215 // once
216 std::set<typename ::internal::
217 ActiveCellIterator<dim, spacedim, MeshType>::type>
219
220 typename ::internal::ActiveCellIterator<dim, spacedim, MeshType>::type
221 cell = mesh.begin_active(),
222 endc = mesh.end();
223
224 // go through all active cells and look if the vertex is part of that cell
225 //
226 // in 1d, this is all we need to care about. in 2d/3d we also need to worry
227 // that the vertex might be a hanging node on a face or edge of a cell; in
228 // this case, we would want to add those cells as well on whose faces the
229 // vertex is located but for which it is not a vertex itself.
230 //
231 // getting this right is a lot simpler in 2d than in 3d. in 2d, a hanging
232 // node can only be in the middle of a face and we can query the neighboring
233 // cell from the current cell. on the other hand, in 3d a hanging node
234 // vertex can also be on an edge but there can be many other cells on
235 // this edge and we can not access them from the cell we are currently
236 // on.
237 //
238 // so, in the 3d case, if we run the algorithm as in 2d, we catch all
239 // those cells for which the vertex we seek is on a *subface*, but we
240 // miss the case of cells for which the vertex we seek is on a
241 // sub-edge for which there is no corresponding sub-face (because the
242 // immediate neighbor behind this face is not refined), see for example
243 // the bits/find_cells_adjacent_to_vertex_6 testcase. thus, if we
244 // haven't yet found the vertex for the current cell we also need to
245 // look at the mid-points of edges
246 //
247 // as a final note, deciding whether a neighbor is actually coarser is
248 // simple in the case of isotropic refinement (we just need to look at
249 // the level of the current and the neighboring cell). however, this
250 // isn't so simple if we have used anisotropic refinement since then
251 // the level of a cell is not indicative of whether it is coarser or
252 // not than the current cell. ultimately, we want to add all cells on
253 // which the vertex is, independent of whether they are coarser or
254 // finer and so in the 2d case below we simply add *any* *active* neighbor.
255 // in the worst case, we add cells multiple times to the adjacent_cells
256 // list, but std::set throws out those cells already entered
257 for (; cell != endc; ++cell)
258 {
259 for (const unsigned int v : cell->vertex_indices())
260 if (cell->vertex_index(v) == vertex)
261 {
262 // OK, we found a cell that contains
263 // the given vertex. We add it
264 // to the list.
265 adjacent_cells.insert(cell);
266
267 // as explained above, in 2+d we need to check whether
268 // this vertex is on a face behind which there is a
269 // (possibly) coarser neighbor. if this is the case,
270 // then we need to also add this neighbor
271 if (dim >= 2)
272 {
273 const auto reference_cell = cell->reference_cell();
274 for (const auto face :
275 reference_cell.faces_for_given_vertex(v))
276 if (!cell->at_boundary(face) &&
277 cell->neighbor(face)->is_active())
278 {
279 // there is a (possibly) coarser cell behind a
280 // face to which the vertex belongs. the
281 // vertex we are looking at is then either a
282 // vertex of that coarser neighbor, or it is a
283 // hanging node on one of the faces of that
284 // cell. in either case, it is adjacent to the
285 // vertex, so add it to the list as well (if
286 // the cell was already in the list then the
287 // std::set makes sure that we get it only
288 // once)
289 adjacent_cells.insert(cell->neighbor(face));
290 }
291 }
292
293 // in any case, we have found a cell, so go to the next cell
294 goto next_cell;
295 }
296
297 // in 3d also loop over the edges
298 if (dim >= 3)
299 {
300 for (unsigned int e = 0; e < cell->n_lines(); ++e)
301 if (cell->line(e)->has_children())
302 // the only place where this vertex could have been
303 // hiding is on the mid-edge point of the edge we
304 // are looking at
305 if (cell->line(e)->child(0)->vertex_index(1) == vertex)
306 {
307 adjacent_cells.insert(cell);
308
309 // jump out of this tangle of nested loops
310 goto next_cell;
311 }
312 }
313
314 // in more than 3d we would probably have to do the same as
315 // above also for even lower-dimensional objects
316 Assert(dim <= 3, ExcNotImplemented());
317
318 // move on to the next cell if we have found the
319 // vertex on the current one
320 next_cell:;
321 }
322
323 // if this was an active vertex then there needs to have been
324 // at least one cell to which it is adjacent!
326
327 // return the result as a vector, rather than the set we built above
328 return std::vector<typename ::internal::
329 ActiveCellIterator<dim, spacedim, MeshType>::type>(
330 adjacent_cells.begin(), adjacent_cells.end());
331 }
332
333
334
335 namespace
336 {
337 template <int dim, template <int, int> class MeshType, int spacedim>
339 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
340 void find_active_cell_around_point_internal(
341 const MeshType<dim, spacedim> &mesh,
342#ifndef _MSC_VER
343 std::set<typename MeshType<dim, spacedim>::active_cell_iterator>
344 &searched_cells,
345 std::set<typename MeshType<dim, spacedim>::active_cell_iterator>
347#else
348 std::set<
349 typename ::internal::
350 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type>
351 &searched_cells,
352 std::set<
353 typename ::internal::
354 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type>
356#endif
357 {
358#ifndef _MSC_VER
359 using cell_iterator =
360 typename MeshType<dim, spacedim>::active_cell_iterator;
361#else
362 using cell_iterator = typename ::internal::
363 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type;
364#endif
365
366 // update the searched cells
367 searched_cells.insert(adjacent_cells.begin(), adjacent_cells.end());
368 // now we to collect all neighbors
369 // of the cells in adjacent_cells we
370 // have not yet searched.
371 std::set<cell_iterator> adjacent_cells_new;
372
373 for (const auto &cell : adjacent_cells)
374 {
375 std::vector<cell_iterator> active_neighbors;
376 get_active_neighbors<MeshType<dim, spacedim>>(cell, active_neighbors);
377 for (unsigned int i = 0; i < active_neighbors.size(); ++i)
378 if (searched_cells.find(active_neighbors[i]) ==
379 searched_cells.end())
380 adjacent_cells_new.insert(active_neighbors[i]);
381 }
382 adjacent_cells.clear();
383 adjacent_cells.insert(adjacent_cells_new.begin(),
384 adjacent_cells_new.end());
385 if (adjacent_cells.empty())
386 {
387 // we haven't found any other cell that would be a
388 // neighbor of a previously found cell, but we know
389 // that we haven't checked all cells yet. that means
390 // that the domain is disconnected. in that case,
391 // choose the first previously untouched cell we
392 // can find
393 cell_iterator it = mesh.begin_active();
394 for (; it != mesh.end(); ++it)
395 if (searched_cells.find(it) == searched_cells.end())
396 {
397 adjacent_cells.insert(it);
398 break;
399 }
400 }
401 }
402 } // namespace
403
404
405
406 template <int dim, template <int, int> class MeshType, int spacedim>
408 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
409#ifndef _MSC_VER
410 typename MeshType<dim, spacedim>::active_cell_iterator
411#else
412 typename ::internal::
413 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type
414#endif
415 find_active_cell_around_point(const MeshType<dim, spacedim> &mesh,
416 const Point<spacedim> &p,
417 const std::vector<bool> &marked_vertices,
418 const double tolerance)
419 {
420 return find_active_cell_around_point<dim, MeshType, spacedim>(
421 get_default_linear_mapping(mesh.get_triangulation()),
422 mesh,
423 p,
424 marked_vertices,
425 tolerance)
426 .first;
427 }
428
429
430
431 template <int dim, template <int, int> class MeshType, int spacedim>
433 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
434#ifndef _MSC_VER
435 std::pair<typename MeshType<dim, spacedim>::active_cell_iterator, Point<dim>>
436#else
437 std::pair<typename ::internal::
438 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type,
440#endif
442 const MeshType<dim, spacedim> &mesh,
443 const Point<spacedim> &p,
444 const std::vector<bool> &marked_vertices,
445 const double tolerance)
446 {
447 using active_cell_iterator = typename ::internal::
448 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type;
449
450 // The best distance is set to the
451 // maximum allowable distance from
452 // the unit cell; we assume a
453 // max. deviation of the given tolerance
454 double best_distance = tolerance;
455 int best_level = -1;
456 std::pair<active_cell_iterator, Point<dim>> best_cell;
457
458 // Initialize best_cell.first to the end iterator
459 best_cell.first = mesh.end();
460
461 // Find closest vertex and determine
462 // all adjacent cells
463 std::vector<active_cell_iterator> adjacent_cells_tmp =
465 mesh, find_closest_vertex(mapping, mesh, p, marked_vertices));
466
467 // Make sure that we have found
468 // at least one cell adjacent to vertex.
469 Assert(adjacent_cells_tmp.size() > 0, ExcInternalError());
470
471 // Copy all the cells into a std::set
472 std::set<active_cell_iterator> adjacent_cells(adjacent_cells_tmp.begin(),
473 adjacent_cells_tmp.end());
474 std::set<active_cell_iterator> searched_cells;
475
476 // Determine the maximal number of cells
477 // in the grid.
478 // As long as we have not found
479 // the cell and have not searched
480 // every cell in the triangulation,
481 // we keep on looking.
482 const auto n_active_cells = mesh.get_triangulation().n_active_cells();
483 bool found = false;
484 unsigned int cells_searched = 0;
485 while (!found && cells_searched < n_active_cells)
486 {
487 for (const auto &cell : adjacent_cells)
488 {
489 if (cell->is_artificial() == false)
490 {
491 // marked_vertices are used to filter cell candidates
492 if (marked_vertices.size() > 0)
493 {
494 bool any_vertex_marked = false;
495 for (const auto &v : cell->vertex_indices())
496 {
497 if (marked_vertices[cell->vertex_index(v)])
498 {
499 any_vertex_marked = true;
500 break;
501 }
502 }
503 if (!any_vertex_marked)
504 continue;
505 }
506
507 try
508 {
509 const Point<dim> p_cell =
510 mapping.transform_real_to_unit_cell(cell, p);
511
512 // calculate the Euclidean norm of
513 // the distance vector to the unit cell.
514 const double dist =
515 cell->reference_cell().closest_point(p_cell).distance(
516 p_cell);
517
518 // We compare if the point is inside the
519 // unit cell (or at least not too far
520 // outside). If it is, it is also checked
521 // that the cell has a more refined state
522 if ((dist < best_distance) ||
523 ((dist == best_distance) &&
524 (cell->level() > best_level)))
525 {
526 found = true;
527 best_distance = dist;
528 best_level = cell->level();
529 best_cell = std::make_pair(cell, p_cell);
530 }
531 }
532 catch (
534 {
535 // ok, the transformation
536 // failed presumably
537 // because the point we
538 // are looking for lies
539 // outside the current
540 // cell. this means that
541 // the current cell can't
542 // be the cell around the
543 // point, so just ignore
544 // this cell and move on
545 // to the next
546 }
547 }
548 }
549
550 // update the number of cells searched
551 cells_searched += adjacent_cells.size();
552
553 // if we have not found the cell in
554 // question and have not yet searched every
555 // cell, we expand our search to
556 // all the not already searched neighbors of
557 // the cells in adjacent_cells. This is
558 // what find_active_cell_around_point_internal
559 // is for.
560 if (!found && cells_searched < n_active_cells)
561 {
562 find_active_cell_around_point_internal<dim, MeshType, spacedim>(
563 mesh, searched_cells, adjacent_cells);
564 }
565 }
566
567 return best_cell;
568 }
569
570
571
572 template <int dim, template <int, int> class MeshType, int spacedim>
574 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
575#ifndef _MSC_VER
576 std::vector<std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
577 Point<dim>>>
578#else
579 std::vector<std::pair<
580 typename ::internal::
581 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type,
582 Point<dim>>>
583#endif
585 const MeshType<dim, spacedim> &mesh,
586 const Point<spacedim> &p,
587 const double tolerance,
588 const std::vector<bool> &marked_vertices)
589 {
590 const auto cell_and_point = find_active_cell_around_point(
591 mapping, mesh, p, marked_vertices, tolerance);
592
593 if (cell_and_point.first == mesh.end())
594 return {};
595
597 mapping, mesh, p, tolerance, cell_and_point);
598 }
599
600
601
602 template <int dim, template <int, int> class MeshType, int spacedim>
604 (concepts::is_triangulation_or_dof_handler<MeshType<dim, spacedim>>))
605#ifndef _MSC_VER
606 std::vector<std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
607 Point<dim>>>
608#else
609 std::vector<std::pair<
610 typename ::internal::
611 ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type,
612 Point<dim>>>
613#endif
615 const Mapping<dim, spacedim> &mapping,
616 const MeshType<dim, spacedim> &mesh,
617 const Point<spacedim> &p,
618 const double tolerance,
619 const std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
620 Point<dim>> &first_cell,
621 const std::vector<
622 std::set<typename MeshType<dim, spacedim>::active_cell_iterator>>
623 *vertex_to_cells)
624 {
625 std::vector<
626 std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
627 Point<dim>>>
628 cells_and_points;
629
630 // insert the fist cell and point into the vector
631 cells_and_points.push_back(first_cell);
632
633 const Point<dim> unit_point = cells_and_points.front().second;
634 const auto my_cell = cells_and_points.front().first;
635
636 std::vector<typename MeshType<dim, spacedim>::active_cell_iterator>
637 cells_to_add;
638
639 if (my_cell->reference_cell().is_hyper_cube())
640 {
641 // check if the given point is on the surface of the unit cell. If yes,
642 // need to find all neighbors
643
644 Tensor<1, dim> distance_to_center;
645 unsigned int n_dirs_at_threshold = 0;
646 unsigned int last_point_at_threshold = numbers::invalid_unsigned_int;
647 for (unsigned int d = 0; d < dim; ++d)
648 {
649 distance_to_center[d] = std::abs(unit_point[d] - 0.5);
650 if (distance_to_center[d] > 0.5 - tolerance)
651 {
652 ++n_dirs_at_threshold;
653 last_point_at_threshold = d;
654 }
655 }
656
657 // point is within face -> only need neighbor
658 if (n_dirs_at_threshold == 1)
659 {
660 unsigned int neighbor_index =
661 2 * last_point_at_threshold +
662 (unit_point[last_point_at_threshold] > 0.5 ? 1 : 0);
663 if (!my_cell->at_boundary(neighbor_index))
664 {
665 const auto neighbor_cell = my_cell->neighbor(neighbor_index);
666
667 if (neighbor_cell->is_active())
668 cells_to_add.push_back(neighbor_cell);
669 else
670 for (const auto &child_cell :
671 neighbor_cell->child_iterators())
672 {
673 if (child_cell->is_active())
674 cells_to_add.push_back(child_cell);
675 }
676 }
677 }
678 // corner point -> use all neighbors
679 else if (n_dirs_at_threshold == dim)
680 {
681 unsigned int local_vertex_index = 0;
682 for (unsigned int d = 0; d < dim; ++d)
683 local_vertex_index += (unit_point[d] > 0.5 ? 1 : 0) << d;
684
685 const auto fu = [&](const auto &tentative_cells) {
686 for (const auto &cell : tentative_cells)
687 if (cell != my_cell)
688 cells_to_add.push_back(cell);
689 };
690
691 const auto vertex_index = my_cell->vertex_index(local_vertex_index);
692
693 if (vertex_to_cells != nullptr)
694 fu((*vertex_to_cells)[vertex_index]);
695 else
696 fu(find_cells_adjacent_to_vertex(mesh, vertex_index));
697 }
698 // point on line in 3d: We cannot simply take the intersection between
699 // the two vertices of cells because of hanging nodes. So instead we
700 // list the vertices around both points and then select the
701 // appropriate cells according to the result of read_to_unit_cell
702 // below.
703 else if (n_dirs_at_threshold == 2)
704 {
705 std::pair<unsigned int, unsigned int> vertex_indices[3];
706 unsigned int count_vertex_indices = 0;
707 unsigned int free_direction = numbers::invalid_unsigned_int;
708 for (unsigned int d = 0; d < dim; ++d)
709 {
710 if (distance_to_center[d] > 0.5 - tolerance)
711 {
712 vertex_indices[count_vertex_indices].first = d;
713 vertex_indices[count_vertex_indices].second =
714 unit_point[d] > 0.5 ? 1 : 0;
715 ++count_vertex_indices;
716 }
717 else
718 free_direction = d;
719 }
720
721 AssertDimension(count_vertex_indices, 2);
722 Assert(free_direction != numbers::invalid_unsigned_int,
724
725 const unsigned int first_vertex =
726 (vertex_indices[0].second << vertex_indices[0].first) +
728 for (unsigned int d = 0; d < 2; ++d)
729 {
730 const auto fu = [&](const auto &tentative_cells) {
731 for (const auto &cell : tentative_cells)
732 {
733 bool cell_not_yet_present = true;
734 for (const auto &other_cell : cells_to_add)
735 if (cell == other_cell)
736 {
737 cell_not_yet_present = false;
738 break;
739 }
740 if (cell_not_yet_present)
741 cells_to_add.push_back(cell);
742 }
743 };
744
745 const auto vertex_index =
746 my_cell->vertex_index(first_vertex + (d << free_direction));
747
748 if (vertex_to_cells != nullptr)
749 fu((*vertex_to_cells)[vertex_index]);
750 else
751 fu(find_cells_adjacent_to_vertex(mesh, vertex_index));
752 }
753 }
754 }
755 else
756 {
757 // Note: The non-hypercube path takes a very naive approach and
758 // checks all possible neighbors. This can be made faster by 1)
759 // checking if the point is in the inner cell and 2) identifying
760 // the right lines/vertices so that the number of potential
761 // neighbors is reduced.
762
763 for (const auto v : my_cell->vertex_indices())
764 {
765 const auto fu = [&](const auto &tentative_cells) {
766 for (const auto &cell : tentative_cells)
767 {
768 bool cell_not_yet_present = true;
769 for (const auto &other_cell : cells_to_add)
770 if (cell == other_cell)
771 {
772 cell_not_yet_present = false;
773 break;
774 }
775 if (cell_not_yet_present)
776 cells_to_add.push_back(cell);
777 }
778 };
779
780 const auto vertex_index = my_cell->vertex_index(v);
781
782 if (vertex_to_cells != nullptr)
783 fu((*vertex_to_cells)[vertex_index]);
784 else
785 fu(find_cells_adjacent_to_vertex(mesh, vertex_index));
786 }
787 }
788
789 for (const auto &cell : cells_to_add)
790 {
791 if (cell != my_cell)
792 try
793 {
794 const Point<dim> p_unit =
795 mapping.transform_real_to_unit_cell(cell, p);
796 if (cell->reference_cell().contains_point(p_unit, tolerance))
797 cells_and_points.emplace_back(cell, p_unit);
798 }
800 {}
801 }
802
803 std::sort(
804 cells_and_points.begin(),
805 cells_and_points.end(),
806 [](const std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
807 Point<dim>> &a,
808 const std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
809 Point<dim>> &b) { return a.first < b.first; });
810
811 return cells_and_points;
812 }
813
814
815
816 template <typename MeshType>
818 std::
819 vector<typename MeshType::active_cell_iterator> compute_active_cell_halo_layer(
820 const MeshType &mesh,
821 const std::function<bool(const typename MeshType::active_cell_iterator &)>
822 &predicate)
823 {
824 std::vector<typename MeshType::active_cell_iterator> active_halo_layer;
825 std::vector<bool> locally_active_vertices_on_subdomain(
826 mesh.get_triangulation().n_vertices(), false);
827
828 std::map<unsigned int, std::vector<unsigned int>> coinciding_vertex_groups;
829 std::map<unsigned int, unsigned int> vertex_to_coinciding_vertex_group;
830 GridTools::collect_coinciding_vertices(mesh.get_triangulation(),
831 coinciding_vertex_groups,
832 vertex_to_coinciding_vertex_group);
833
834 // Find the cells for which the predicate is true
835 // These are the cells around which we wish to construct
836 // the halo layer
837 for (const auto &cell : mesh.active_cell_iterators())
838 if (predicate(cell)) // True predicate --> Part of subdomain
839 for (const auto v : cell->vertex_indices())
840 {
841 locally_active_vertices_on_subdomain[cell->vertex_index(v)] = true;
842
843 const auto group =
844 vertex_to_coinciding_vertex_group.find(cell->vertex_index(v));
845 if (group != vertex_to_coinciding_vertex_group.end())
846 for (const auto vv : coinciding_vertex_groups[group->second])
847 locally_active_vertices_on_subdomain[vv] = true;
848 }
849
850 // Find the cells that do not conform to the predicate
851 // but share a vertex with the selected subdomain
852 // These comprise the halo layer
853 for (const auto &cell : mesh.active_cell_iterators())
854 if (!predicate(cell)) // False predicate --> Potential halo cell
855 for (const auto v : cell->vertex_indices())
856 if (locally_active_vertices_on_subdomain[cell->vertex_index(v)] ==
857 true)
858 {
859 active_halo_layer.push_back(cell);
860 break;
861 }
862
863 return active_halo_layer;
864 }
865
866
867
868 template <typename MeshType>
870 std::
871 vector<typename MeshType::cell_iterator> compute_cell_halo_layer_on_level(
872 const MeshType &mesh,
873 const std::function<bool(const typename MeshType::cell_iterator &)>
874 &predicate,
875 const unsigned int level)
876 {
877 std::vector<typename MeshType::cell_iterator> level_halo_layer;
878 std::vector<bool> locally_active_vertices_on_level_subdomain(
879 mesh.get_triangulation().n_vertices(), false);
880
881 // Find the cells for which the predicate is true
882 // These are the cells around which we wish to construct
883 // the halo layer
884 for (typename MeshType::cell_iterator cell = mesh.begin(level);
885 cell != mesh.end(level);
886 ++cell)
887 if (predicate(cell)) // True predicate --> Part of subdomain
888 for (const unsigned int v : cell->vertex_indices())
889 locally_active_vertices_on_level_subdomain[cell->vertex_index(v)] =
890 true;
891
892 // Find the cells that do not conform to the predicate
893 // but share a vertex with the selected subdomain on that level
894 // These comprise the halo layer
895 for (typename MeshType::cell_iterator cell = mesh.begin(level);
896 cell != mesh.end(level);
897 ++cell)
898 if (!predicate(cell)) // False predicate --> Potential halo cell
899 for (const unsigned int v : cell->vertex_indices())
900 if (locally_active_vertices_on_level_subdomain[cell->vertex_index(
901 v)] == true)
902 {
903 level_halo_layer.push_back(cell);
904 break;
905 }
906
907 return level_halo_layer;
908 }
909
910
911 namespace
912 {
913 template <typename MeshType>
915 bool contains_locally_owned_cells(
916 const std::vector<typename MeshType::active_cell_iterator> &cells)
917 {
918 for (typename std::vector<
919 typename MeshType::active_cell_iterator>::const_iterator it =
920 cells.begin();
921 it != cells.end();
922 ++it)
923 {
924 if ((*it)->is_locally_owned())
925 return true;
926 }
927 return false;
928 }
929
930 template <typename MeshType>
932 bool contains_artificial_cells(
933 const std::vector<typename MeshType::active_cell_iterator> &cells)
934 {
935 for (typename std::vector<
936 typename MeshType::active_cell_iterator>::const_iterator it =
937 cells.begin();
938 it != cells.end();
939 ++it)
940 {
941 if ((*it)->is_artificial())
942 return true;
943 }
944 return false;
945 }
946 } // namespace
947
948
949
950 template <typename MeshType>
952 std::vector<
953 typename MeshType::
954 active_cell_iterator> compute_ghost_cell_halo_layer(const MeshType &mesh)
955 {
956 std::function<bool(const typename MeshType::active_cell_iterator &)>
958
959 const std::vector<typename MeshType::active_cell_iterator>
960 active_halo_layer = compute_active_cell_halo_layer(mesh, predicate);
961
962 // Check that we never return locally owned or artificial cells
963 // What is left should only be the ghost cells
964 Assert(contains_locally_owned_cells<MeshType>(active_halo_layer) == false,
965 ExcMessage("Halo layer contains locally owned cells"));
966 Assert(contains_artificial_cells<MeshType>(active_halo_layer) == false,
967 ExcMessage("Halo layer contains artificial cells"));
968
969 return active_halo_layer;
970 }
971
972
973
974 template <typename MeshType>
976 std::
977 vector<typename MeshType::active_cell_iterator> compute_active_cell_layer_within_distance(
978 const MeshType &mesh,
979 const std::function<bool(const typename MeshType::active_cell_iterator &)>
980 &predicate,
981 const double layer_thickness)
982 {
983 std::vector<typename MeshType::active_cell_iterator>
984 subdomain_boundary_cells, active_cell_layer_within_distance;
985 std::vector<bool> vertices_outside_subdomain(
986 mesh.get_triangulation().n_vertices(), false);
987
988 const unsigned int spacedim = MeshType::space_dimension;
989
990 unsigned int n_non_predicate_cells = 0; // Number of non predicate cells
991
992 // Find the layer of cells for which predicate is true and that
993 // are on the boundary with other cells. These are
994 // subdomain boundary cells.
995
996 // Find the cells for which the predicate is false
997 // These are the cells which are around the predicate subdomain
998 for (const auto &cell : mesh.active_cell_iterators())
999 if (!predicate(cell)) // Negation of predicate --> Not Part of subdomain
1000 {
1001 for (const unsigned int v : cell->vertex_indices())
1002 vertices_outside_subdomain[cell->vertex_index(v)] = true;
1003 ++n_non_predicate_cells;
1004 }
1005
1006 // If all the active cells conform to the predicate
1007 // or if none of the active cells conform to the predicate
1008 // there is no active cell layer around the predicate
1009 // subdomain (within any distance)
1010 if (n_non_predicate_cells == 0 ||
1011 n_non_predicate_cells == mesh.get_triangulation().n_active_cells())
1012 return std::vector<typename MeshType::active_cell_iterator>();
1013
1014 // Find the cells that conform to the predicate
1015 // but share a vertex with the cell not in the predicate subdomain
1016 for (const auto &cell : mesh.active_cell_iterators())
1017 if (predicate(cell)) // True predicate --> Potential boundary cell of the
1018 // subdomain
1019 for (const unsigned int v : cell->vertex_indices())
1020 if (vertices_outside_subdomain[cell->vertex_index(v)] == true)
1021 {
1022 subdomain_boundary_cells.push_back(cell);
1023 break; // No need to go through remaining vertices
1024 }
1025
1026 // To cheaply filter out some cells located far away from the predicate
1027 // subdomain, get the bounding box of the predicate subdomain.
1028 std::pair<Point<spacedim>, Point<spacedim>> bounding_box =
1029 compute_bounding_box(mesh, predicate);
1030
1031 // DOUBLE_EPSILON to compare really close double values
1032 const double DOUBLE_EPSILON = 100. * std::numeric_limits<double>::epsilon();
1033
1034 // Add layer_thickness to the bounding box
1035 for (unsigned int d = 0; d < spacedim; ++d)
1036 {
1037 bounding_box.first[d] -= (layer_thickness + DOUBLE_EPSILON); // minp
1038 bounding_box.second[d] += (layer_thickness + DOUBLE_EPSILON); // maxp
1039 }
1040
1041 std::vector<Point<spacedim>>
1042 subdomain_boundary_cells_centers; // cache all the subdomain boundary
1043 // cells centers here
1044 std::vector<double>
1045 subdomain_boundary_cells_radii; // cache all the subdomain boundary cells
1046 // radii
1047 subdomain_boundary_cells_centers.reserve(subdomain_boundary_cells.size());
1048 subdomain_boundary_cells_radii.reserve(subdomain_boundary_cells.size());
1049 // compute cell radius for each boundary cell of the predicate subdomain
1050 for (typename std::vector<typename MeshType::active_cell_iterator>::
1051 const_iterator subdomain_boundary_cell_iterator =
1052 subdomain_boundary_cells.begin();
1053 subdomain_boundary_cell_iterator != subdomain_boundary_cells.end();
1054 ++subdomain_boundary_cell_iterator)
1055 {
1056 const std::pair<Point<spacedim>, double>
1057 &subdomain_boundary_cell_enclosing_ball =
1058 (*subdomain_boundary_cell_iterator)->enclosing_ball();
1059
1060 subdomain_boundary_cells_centers.push_back(
1061 subdomain_boundary_cell_enclosing_ball.first);
1062 subdomain_boundary_cells_radii.push_back(
1063 subdomain_boundary_cell_enclosing_ball.second);
1064 }
1065 AssertThrow(subdomain_boundary_cells_radii.size() ==
1066 subdomain_boundary_cells_centers.size(),
1068
1069 // Find the cells that are within layer_thickness of predicate subdomain
1070 // boundary distance but are inside the extended bounding box. Most cells
1071 // might be outside the extended bounding box, so we could skip them. Those
1072 // cells that are inside the extended bounding box but are not part of the
1073 // predicate subdomain are possible candidates to be within the distance to
1074 // the boundary cells of the predicate subdomain.
1075 for (const auto &cell : mesh.active_cell_iterators())
1076 {
1077 // Ignore all the cells that are in the predicate subdomain
1078 if (predicate(cell))
1079 continue;
1080
1081 const std::pair<Point<spacedim>, double> &cell_enclosing_ball =
1082 cell->enclosing_ball();
1083
1084 const Point<spacedim> cell_enclosing_ball_center =
1085 cell_enclosing_ball.first;
1086 const double cell_enclosing_ball_radius = cell_enclosing_ball.second;
1087
1088 bool cell_inside = true; // reset for each cell
1089
1090 for (unsigned int d = 0; d < spacedim; ++d)
1091 cell_inside &=
1092 (cell_enclosing_ball_center[d] + cell_enclosing_ball_radius >
1093 bounding_box.first[d]) &&
1094 (cell_enclosing_ball_center[d] - cell_enclosing_ball_radius <
1095 bounding_box.second[d]);
1096 // cell_inside is true if its enclosing ball intersects the extended
1097 // bounding box
1098
1099 // Ignore all the cells that are outside the extended bounding box
1100 if (cell_inside)
1101 for (unsigned int i = 0; i < subdomain_boundary_cells_radii.size();
1102 ++i)
1103 if (cell_enclosing_ball_center.distance_square(
1104 subdomain_boundary_cells_centers[i]) <
1105 Utilities::fixed_power<2>(cell_enclosing_ball_radius +
1106 subdomain_boundary_cells_radii[i] +
1107 layer_thickness + DOUBLE_EPSILON))
1108 {
1109 active_cell_layer_within_distance.push_back(cell);
1110 break; // Exit the loop checking all the remaining subdomain
1111 // boundary cells
1112 }
1113 }
1114 return active_cell_layer_within_distance;
1115 }
1116
1117
1118
1119 template <typename MeshType>
1121 std::vector<
1122 typename MeshType::
1123 active_cell_iterator> compute_ghost_cell_layer_within_distance(const MeshType
1124 &mesh,
1125 const double
1126 layer_thickness)
1127 {
1128 IteratorFilters::LocallyOwnedCell locally_owned_cell_predicate;
1129 std::function<bool(const typename MeshType::active_cell_iterator &)>
1130 predicate(locally_owned_cell_predicate);
1131
1132 const std::vector<typename MeshType::active_cell_iterator>
1133 ghost_cell_layer_within_distance =
1135 predicate,
1136 layer_thickness);
1137
1138 // Check that we never return locally owned or artificial cells
1139 // What is left should only be the ghost cells
1140 Assert(
1141 contains_locally_owned_cells<MeshType>(
1142 ghost_cell_layer_within_distance) == false,
1143 ExcMessage(
1144 "Ghost cells within layer_thickness contains locally owned cells."));
1145 Assert(
1146 contains_artificial_cells<MeshType>(ghost_cell_layer_within_distance) ==
1147 false,
1148 ExcMessage(
1149 "Ghost cells within layer_thickness contains artificial cells. "
1150 "The function compute_ghost_cell_layer_within_distance "
1151 "is probably called while using parallel::distributed::Triangulation. "
1152 "In such case please refer to the description of this function."));
1153
1154 return ghost_cell_layer_within_distance;
1155 }
1156
1157
1158
1159 template <typename MeshType>
1161 std::pair<
1163 Point<MeshType::
1164 space_dimension>> compute_bounding_box(const MeshType &mesh,
1165 const std::function<bool(
1166 const typename MeshType::
1167 active_cell_iterator &)>
1168 &predicate)
1169 {
1170 std::vector<bool> locally_active_vertices_on_subdomain(
1171 mesh.get_triangulation().n_vertices(), false);
1172
1173 const unsigned int spacedim = MeshType::space_dimension;
1174
1175 // Two extreme points can define the bounding box
1176 // around the active cells that conform to the given predicate.
1178
1179 // initialize minp and maxp with the first predicate cell center
1180 for (const auto &cell : mesh.active_cell_iterators())
1181 if (predicate(cell))
1182 {
1183 minp = cell->center();
1184 maxp = cell->center();
1185 break;
1186 }
1187
1188 // Run through all the cells to check if it belongs to predicate domain,
1189 // if it belongs to the predicate domain, extend the bounding box.
1190 for (const auto &cell : mesh.active_cell_iterators())
1191 if (predicate(cell)) // True predicate --> Part of subdomain
1192 for (const unsigned int v : cell->vertex_indices())
1193 if (locally_active_vertices_on_subdomain[cell->vertex_index(v)] ==
1194 false)
1195 {
1196 locally_active_vertices_on_subdomain[cell->vertex_index(v)] =
1197 true;
1198 for (unsigned int d = 0; d < spacedim; ++d)
1199 {
1200 minp[d] = std::min(minp[d], cell->vertex(v)[d]);
1201 maxp[d] = std::max(maxp[d], cell->vertex(v)[d]);
1202 }
1203 }
1204
1205 return std::make_pair(minp, maxp);
1206 }
1207
1208
1209
1210 template <typename MeshType>
1212 std::list<std::pair<
1213 typename MeshType::cell_iterator,
1214 typename MeshType::cell_iterator>> get_finest_common_cells(const MeshType
1215 &mesh_1,
1216 const MeshType
1217 &mesh_2)
1218 {
1219 Assert(have_same_coarse_mesh(mesh_1, mesh_2),
1220 ExcMessage("The two meshes must be represent triangulations that "
1221 "have the same coarse meshes"));
1222 // We will allow the output to contain ghost cells when we have shared
1223 // Triangulations (i.e., so that each processor will get exactly the same
1224 // list of cell pairs), but not when we have two distributed
1225 // Triangulations (so that all active cells are partitioned by processor).
1226 // Non-parallel Triangulations have no ghost or artificial cells, so they
1227 // work the same way as shared Triangulations here.
1228 bool remove_ghost_cells = false;
1229#ifdef DEAL_II_WITH_MPI
1230 {
1231 constexpr int dim = MeshType::dimension;
1232 constexpr int spacedim = MeshType::space_dimension;
1234 *>(&mesh_1.get_triangulation()) != nullptr ||
1236 *>(&mesh_2.get_triangulation()) != nullptr)
1237 {
1238 Assert(&mesh_1.get_triangulation() == &mesh_2.get_triangulation(),
1239 ExcMessage("This function can only be used with meshes "
1240 "corresponding to distributed Triangulations when "
1241 "both Triangulations are equal."));
1242 remove_ghost_cells = true;
1243 }
1244 }
1245#endif
1246
1247 // the algorithm goes as follows: first, we fill a list with pairs of
1248 // iterators common to the two meshes on the coarsest level. then we
1249 // traverse the list; each time, we find a pair of iterators for which
1250 // both correspond to non-active cells, we delete this item and push the
1251 // pairs of iterators to their children to the back. if these again both
1252 // correspond to non-active cells, we will get to the later on for further
1253 // consideration
1254 using CellList = std::list<std::pair<typename MeshType::cell_iterator,
1255 typename MeshType::cell_iterator>>;
1256 CellList cell_list;
1257
1258 // first push the coarse level cells
1259 typename MeshType::cell_iterator cell_1 = mesh_1.begin(0),
1260 cell_2 = mesh_2.begin(0);
1261 for (; cell_1 != mesh_1.end(0); ++cell_1, ++cell_2)
1262 cell_list.emplace_back(cell_1, cell_2);
1263
1264 // then traverse list as described above
1265 typename CellList::iterator cell_pair = cell_list.begin();
1266 while (cell_pair != cell_list.end())
1267 {
1268 // if both cells in this pair have children, then erase this element
1269 // and push their children instead
1270 if (cell_pair->first->has_children() &&
1271 cell_pair->second->has_children())
1272 {
1273 Assert(cell_pair->first->refinement_case() ==
1274 cell_pair->second->refinement_case(),
1276 for (unsigned int c = 0; c < cell_pair->first->n_children(); ++c)
1277 cell_list.emplace_back(cell_pair->first->child(c),
1278 cell_pair->second->child(c));
1279
1280 // erasing an iterator keeps other iterators valid, so already
1281 // advance the present iterator by one and then delete the element
1282 // we've visited before
1283 const auto previous_cell_pair = cell_pair;
1284 ++cell_pair;
1285 cell_list.erase(previous_cell_pair);
1286 }
1287 else
1288 {
1289 // at least one cell is active
1290 if (remove_ghost_cells &&
1291 ((cell_pair->first->is_active() &&
1292 !cell_pair->first->is_locally_owned()) ||
1293 (cell_pair->second->is_active() &&
1294 !cell_pair->second->is_locally_owned())))
1295 {
1296 // we only exclude ghost cells for distributed Triangulations
1297 const auto previous_cell_pair = cell_pair;
1298 ++cell_pair;
1299 cell_list.erase(previous_cell_pair);
1300 }
1301 else
1302 ++cell_pair;
1303 }
1304 }
1305
1306 // just to make sure everything is ok, validate that all pairs have at
1307 // least one active iterator or have different refinement_cases
1308 for (cell_pair = cell_list.begin(); cell_pair != cell_list.end();
1309 ++cell_pair)
1310 Assert(cell_pair->first->is_active() || cell_pair->second->is_active() ||
1311 (cell_pair->first->refinement_case() !=
1312 cell_pair->second->refinement_case()),
1314
1315 return cell_list;
1316 }
1317
1318
1319
1320 template <int dim, int spacedim>
1321 bool
1323 const Triangulation<dim, spacedim> &mesh_2)
1324 {
1325 // make sure the two meshes have
1326 // the same number of coarse cells
1327 if (mesh_1.n_cells(0) != mesh_2.n_cells(0))
1328 return false;
1329
1330 // if so, also make sure they have
1331 // the same vertices on the cells
1332 // of the coarse mesh
1334 mesh_1.begin(0),
1335 cell_2 =
1336 mesh_2.begin(0),
1337 endc = mesh_1.end(0);
1338 for (; cell_1 != endc; ++cell_1, ++cell_2)
1339 {
1340 if (cell_1->n_vertices() != cell_2->n_vertices())
1341 return false;
1342 for (const unsigned int v : cell_1->vertex_indices())
1343 if (cell_1->vertex(v) != cell_2->vertex(v))
1344 return false;
1345 }
1346
1347 // if we've gotten through all
1348 // this, then the meshes really
1349 // seem to have a common coarse
1350 // mesh
1351 return true;
1352 }
1353
1354
1355
1356 template <typename MeshType>
1358 bool have_same_coarse_mesh(const MeshType &mesh_1, const MeshType &mesh_2)
1359 {
1360 return have_same_coarse_mesh(mesh_1.get_triangulation(),
1361 mesh_2.get_triangulation());
1362 }
1363
1364
1365
1366 template <int dim, int spacedim>
1367 std::pair<typename DoFHandler<dim, spacedim>::active_cell_iterator,
1368 Point<dim>>
1371 const DoFHandler<dim, spacedim> &mesh,
1372 const Point<spacedim> &p,
1373 const double tolerance)
1374 {
1375 Assert((mapping.size() == 1) ||
1376 (mapping.size() == mesh.get_fe_collection().size()),
1377 ExcMessage("Mapping collection needs to have either size 1 "
1378 "or size equal to the number of elements in "
1379 "the FECollection."));
1380
1381 using cell_iterator =
1383
1384 std::pair<cell_iterator, Point<dim>> best_cell;
1385 // If we have only one element in the MappingCollection,
1386 // we use find_active_cell_around_point using only one
1387 // mapping.
1388 if (mapping.size() == 1)
1389 {
1390 const std::vector<bool> marked_vertices = {};
1392 mapping[0], mesh, p, marked_vertices, tolerance);
1393 }
1394 else
1395 {
1396 // The best distance is set to the
1397 // maximum allowable distance from
1398 // the unit cell
1399 double best_distance = tolerance;
1400 int best_level = -1;
1401
1402
1403 // Find closest vertex and determine
1404 // all adjacent cells
1405 unsigned int vertex = find_closest_vertex(mesh, p);
1406
1407 std::vector<cell_iterator> adjacent_cells_tmp =
1408 find_cells_adjacent_to_vertex(mesh, vertex);
1409
1410 // Make sure that we have found
1411 // at least one cell adjacent to vertex.
1412 Assert(adjacent_cells_tmp.size() > 0, ExcInternalError());
1413
1414 // Copy all the cells into a std::set
1415 std::set<cell_iterator> adjacent_cells(adjacent_cells_tmp.begin(),
1416 adjacent_cells_tmp.end());
1417 std::set<cell_iterator> searched_cells;
1418
1419 // Determine the maximal number of cells
1420 // in the grid.
1421 // As long as we have not found
1422 // the cell and have not searched
1423 // every cell in the triangulation,
1424 // we keep on looking.
1425 const auto n_cells = mesh.get_triangulation().n_cells();
1426 bool found = false;
1427 unsigned int cells_searched = 0;
1428 while (!found && cells_searched < n_cells)
1429 {
1430 for (const auto &cell : adjacent_cells)
1431 {
1432 try
1433 {
1434 const Point<dim> p_cell =
1435 mapping[cell->active_fe_index()]
1436 .transform_real_to_unit_cell(cell, p);
1437
1438
1439 // calculate the Euclidean norm of
1440 // the distance vector to the unit cell.
1441 const double dist =
1442 cell->reference_cell().closest_point(p_cell).distance(
1443 p_cell);
1444
1445 // We compare if the point is inside the
1446 // unit cell (or at least not too far
1447 // outside). If it is, it is also checked
1448 // that the cell has a more refined state
1449 if (dist < best_distance ||
1450 (dist == best_distance && cell->level() > best_level))
1451 {
1452 found = true;
1453 best_distance = dist;
1454 best_level = cell->level();
1455 best_cell = std::make_pair(cell, p_cell);
1456 }
1457 }
1458 catch (
1460 {
1461 // ok, the transformation
1462 // failed presumably
1463 // because the point we
1464 // are looking for lies
1465 // outside the current
1466 // cell. this means that
1467 // the current cell can't
1468 // be the cell around the
1469 // point, so just ignore
1470 // this cell and move on
1471 // to the next
1472 }
1473 }
1474 // update the number of cells searched
1475 cells_searched += adjacent_cells.size();
1476 // if we have not found the cell in
1477 // question and have not yet searched every
1478 // cell, we expand our search to
1479 // all the not already searched neighbors of
1480 // the cells in adjacent_cells.
1481 if (!found && cells_searched < n_cells)
1482 {
1483 find_active_cell_around_point_internal<dim,
1484 DoFHandler,
1485 spacedim>(
1486 mesh, searched_cells, adjacent_cells);
1487 }
1488 }
1489 }
1490
1491 return best_cell;
1492 }
1493
1494
1495 template <typename MeshType>
1497 std::vector<typename MeshType::active_cell_iterator> get_patch_around_cell(
1498 const typename MeshType::active_cell_iterator &cell)
1499 {
1500 Assert(cell->is_locally_owned(),
1501 ExcMessage("This function only makes sense if the cell for "
1502 "which you are asking for a patch, is locally "
1503 "owned."));
1504
1505 std::vector<typename MeshType::active_cell_iterator> patch;
1506 patch.push_back(cell);
1507 for (const unsigned int face_number : cell->face_indices())
1508 if (cell->face(face_number)->at_boundary() == false)
1509 {
1510 if (cell->neighbor(face_number)->has_children() == false)
1511 patch.push_back(cell->neighbor(face_number));
1512 else
1513 // the neighbor is refined. in 2d/3d, we can simply ask for the
1514 // children of the neighbor because they can not be further refined
1515 // and, consequently, the children is active
1516 if (MeshType::dimension > 1)
1517 {
1518 for (unsigned int subface = 0;
1519 subface < cell->face(face_number)->n_children();
1520 ++subface)
1521 patch.push_back(
1522 cell->neighbor_child_on_subface(face_number, subface));
1523 }
1524 else
1525 {
1526 // in 1d, we need to work a bit harder: iterate until we find
1527 // the child by going from cell to child to child etc
1528 typename MeshType::cell_iterator neighbor =
1529 cell->neighbor(face_number);
1530 while (neighbor->has_children())
1531 neighbor = neighbor->child(1 - face_number);
1532
1533 Assert(neighbor->neighbor(1 - face_number) == cell,
1535 patch.push_back(neighbor);
1536 }
1537 }
1538 return patch;
1539 }
1540
1541
1542
1543 template <class Container>
1544 std::vector<typename Container::cell_iterator>
1546 const std::vector<typename Container::active_cell_iterator> &patch)
1547 {
1548 Assert(patch.size() > 0,
1549 ExcMessage(
1550 "Vector containing patch cells should not be an empty vector!"));
1551 // In order to extract the set of cells with the coarsest common level from
1552 // the give vector of cells: First it finds the number associated with the
1553 // minimum level of refinement, namely "min_level"
1554 int min_level = patch[0]->level();
1555
1556 for (unsigned int i = 0; i < patch.size(); ++i)
1557 min_level = std::min(min_level, patch[i]->level());
1558 std::set<typename Container::cell_iterator> uniform_cells;
1559 typename std::vector<
1560 typename Container::active_cell_iterator>::const_iterator patch_cell;
1561 // it loops through all cells of the input vector
1562 for (patch_cell = patch.begin(); patch_cell != patch.end(); ++patch_cell)
1563 {
1564 // If the refinement level of each cell i the loop be equal to the
1565 // min_level, so that that cell inserted into the set of uniform_cells,
1566 // as the set of cells with the coarsest common refinement level
1567 if ((*patch_cell)->level() == min_level)
1568 uniform_cells.insert(*patch_cell);
1569 else
1570 // If not, it asks for the parent of the cell, until it finds the
1571 // parent cell with the refinement level equal to the min_level and
1572 // inserts that parent cell into the set of uniform_cells, as the
1573 // set of cells with the coarsest common refinement level.
1574 {
1575 typename Container::cell_iterator parent = *patch_cell;
1576
1577 while (parent->level() > min_level)
1578 parent = parent->parent();
1579 uniform_cells.insert(parent);
1580 }
1581 }
1582
1583 return std::vector<typename Container::cell_iterator>(uniform_cells.begin(),
1584 uniform_cells.end());
1585 }
1586
1587
1588
1589 template <class Container>
1590 void
1592 const std::vector<typename Container::active_cell_iterator> &patch,
1594 &local_triangulation,
1595 std::map<
1596 typename Triangulation<Container::dimension,
1597 Container::space_dimension>::active_cell_iterator,
1598 typename Container::active_cell_iterator> &patch_to_global_tria_map)
1599
1600 {
1601 const std::vector<typename Container::cell_iterator> uniform_cells =
1602 get_cells_at_coarsest_common_level<Container>(patch);
1603 // First it creates triangulation from the vector of "uniform_cells"
1604 local_triangulation.clear();
1605 std::vector<Point<Container::space_dimension>> vertices;
1606 const unsigned int n_uniform_cells = uniform_cells.size();
1607 std::vector<CellData<Container::dimension>> cells(n_uniform_cells);
1608 unsigned int k = 0; // for enumerating cells
1609 unsigned int i = 0; // for enumerating vertices
1610 typename std::vector<typename Container::cell_iterator>::const_iterator
1611 uniform_cell;
1612 for (uniform_cell = uniform_cells.begin();
1613 uniform_cell != uniform_cells.end();
1614 ++uniform_cell)
1615 {
1616 for (const unsigned int v : (*uniform_cell)->vertex_indices())
1617 {
1619 (*uniform_cell)->vertex(v);
1620 bool repeat_vertex = false;
1621
1622 for (unsigned int m = 0; m < i; ++m)
1623 {
1624 if (position == vertices[m])
1625 {
1626 repeat_vertex = true;
1627 cells[k].vertices[v] = m;
1628 break;
1629 }
1630 }
1631 if (repeat_vertex == false)
1632 {
1633 vertices.push_back(position);
1634 cells[k].vertices[v] = i;
1635 i = i + 1;
1636 }
1637
1638 } // for vertices_per_cell
1639 k = k + 1;
1640 }
1641 local_triangulation.create_triangulation(vertices, cells, SubCellData());
1642 Assert(local_triangulation.n_active_cells() == uniform_cells.size(),
1644 local_triangulation.clear_user_flags();
1645 unsigned int index = 0;
1646 // Create a map between cells of class DoFHandler into class Triangulation
1647 std::map<typename Triangulation<Container::dimension,
1648 Container::space_dimension>::cell_iterator,
1649 typename Container::cell_iterator>
1650 patch_to_global_tria_map_tmp;
1651 for (typename Triangulation<Container::dimension,
1652 Container::space_dimension>::cell_iterator
1653 coarse_cell = local_triangulation.begin();
1654 coarse_cell != local_triangulation.end();
1655 ++coarse_cell, ++index)
1656 {
1657 patch_to_global_tria_map_tmp.insert(
1658 std::make_pair(coarse_cell, uniform_cells[index]));
1659 // To ensure that the cells with the same coordinates (here, we compare
1660 // their centers) are mapped into each other.
1661
1662 Assert(coarse_cell->center().distance(uniform_cells[index]->center()) <=
1663 1e-15 * coarse_cell->diameter(),
1665 }
1666 bool refinement_necessary;
1667 // In this loop we start to do refinement on the above coarse triangulation
1668 // to reach to the same level of refinement as the patch cells are really on
1669 do
1670 {
1671 refinement_necessary = false;
1672 for (const auto &active_tria_cell :
1673 local_triangulation.active_cell_iterators())
1674 {
1675 if (patch_to_global_tria_map_tmp[active_tria_cell]->has_children())
1676 {
1677 active_tria_cell->set_refine_flag();
1678 refinement_necessary = true;
1679 }
1680 else
1681 for (unsigned int i = 0; i < patch.size(); ++i)
1682 {
1683 // Even though vertices may not be exactly the same, the
1684 // appropriate cells will match since == for TriAccessors
1685 // checks only cell level and index.
1686 if (patch_to_global_tria_map_tmp[active_tria_cell] ==
1687 patch[i])
1688 {
1689 // adjust the cell vertices of the local_triangulation to
1690 // match cell vertices of the global triangulation
1691 for (const unsigned int v :
1692 active_tria_cell->vertex_indices())
1693 active_tria_cell->vertex(v) = patch[i]->vertex(v);
1694
1695 Assert(active_tria_cell->center().distance(
1696 patch_to_global_tria_map_tmp[active_tria_cell]
1697 ->center()) <=
1698 1e-15 * active_tria_cell->diameter(),
1700
1701 active_tria_cell->set_user_flag();
1702 break;
1703 }
1704 }
1705 }
1706
1707 if (refinement_necessary)
1708 {
1709 local_triangulation.execute_coarsening_and_refinement();
1710
1711 for (typename Triangulation<
1712 Container::dimension,
1713 Container::space_dimension>::cell_iterator cell =
1714 local_triangulation.begin();
1715 cell != local_triangulation.end();
1716 ++cell)
1717 {
1718 if (patch_to_global_tria_map_tmp.find(cell) !=
1719 patch_to_global_tria_map_tmp.end())
1720 {
1721 if (cell->has_children())
1722 {
1723 // Note: Since the cell got children, then it should not
1724 // be in the map anymore children may be added into the
1725 // map, instead
1726
1727 // these children may not yet be in the map
1728 for (unsigned int c = 0; c < cell->n_children(); ++c)
1729 {
1730 if (patch_to_global_tria_map_tmp.find(cell->child(
1731 c)) == patch_to_global_tria_map_tmp.end())
1732 {
1733 patch_to_global_tria_map_tmp.insert(
1734 std::make_pair(
1735 cell->child(c),
1736 patch_to_global_tria_map_tmp[cell]->child(
1737 c)));
1738
1739 // One might be tempted to assert that the cell
1740 // being added here has the same center as the
1741 // equivalent cell in the global triangulation,
1742 // but it may not be the case. For
1743 // triangulations that have been perturbed or
1744 // smoothed, the cell indices and levels may be
1745 // the same, but the vertex locations may not.
1746 // We adjust the vertices of the cells that have
1747 // no children (ie the active cells) to be
1748 // consistent with the global triangulation
1749 // later on and add assertions at that time
1750 // to guarantee the cells in the
1751 // local_triangulation are physically at the
1752 // same locations of the cells in the patch of
1753 // the global triangulation.
1754 }
1755 }
1756 // The parent cell whose children were added
1757 // into the map should be deleted from the map
1758 patch_to_global_tria_map_tmp.erase(cell);
1759 }
1760 }
1761 }
1762 }
1763 }
1764 while (refinement_necessary);
1765
1766
1767 // Last assertion check to make sure we have the right cells and centers
1768 // in the map, and hence the correct vertices of the triangulation
1769 for (typename Triangulation<Container::dimension,
1770 Container::space_dimension>::cell_iterator
1771 cell = local_triangulation.begin();
1772 cell != local_triangulation.end();
1773 ++cell)
1774 {
1775 if (cell->user_flag_set())
1776 {
1777 Assert(patch_to_global_tria_map_tmp.find(cell) !=
1778 patch_to_global_tria_map_tmp.end(),
1780
1781 Assert(cell->center().distance(
1782 patch_to_global_tria_map_tmp[cell]->center()) <=
1783 1e-15 * cell->diameter(),
1785 }
1786 }
1787
1788
1789 typename std::map<
1790 typename Triangulation<Container::dimension,
1791 Container::space_dimension>::cell_iterator,
1792 typename Container::cell_iterator>::iterator
1793 map_tmp_it = patch_to_global_tria_map_tmp.begin(),
1794 map_tmp_end = patch_to_global_tria_map_tmp.end();
1795 // Now we just need to take the temporary map of pairs of type cell_iterator
1796 // "patch_to_global_tria_map_tmp" making pair of active_cell_iterators so
1797 // that filling out the final map "patch_to_global_tria_map"
1798 for (; map_tmp_it != map_tmp_end; ++map_tmp_it)
1799 patch_to_global_tria_map[map_tmp_it->first] = map_tmp_it->second;
1800 }
1801
1802
1803
1804 template <int dim, int spacedim>
1805 std::map<
1807 std::vector<typename DoFHandler<dim, spacedim>::active_cell_iterator>>
1809 {
1810 // This is the map from global_dof_index to
1811 // a set of cells on patch. We first map into
1812 // a set because it is very likely that we
1813 // will attempt to add a cell more than once
1814 // to a particular patch and we want to preserve
1815 // uniqueness of cell iterators. std::set does this
1816 // automatically for us. Later after it is all
1817 // constructed, we will copy to a map of vectors
1818 // since that is the preferred output for other
1819 // functions.
1820 std::map<types::global_dof_index,
1821 std::set<typename DoFHandler<dim, spacedim>::active_cell_iterator>>
1822 dof_to_set_of_cells_map;
1823
1824 std::vector<types::global_dof_index> local_dof_indices;
1825 std::vector<types::global_dof_index> local_face_dof_indices;
1826 std::vector<types::global_dof_index> local_line_dof_indices;
1827
1828 // a place to save the dof_handler user flags and restore them later
1829 // to maintain const of dof_handler.
1830 std::vector<bool> user_flags;
1831
1832
1833 // in 3d, we need pointers from active lines to the
1834 // active parent lines, so we construct it as needed.
1835 std::map<typename DoFHandler<dim, spacedim>::active_line_iterator,
1837 lines_to_parent_lines_map;
1838 if (dim == 3)
1839 {
1840 // save user flags as they will be modified and then later restored
1841 dof_handler.get_triangulation().save_user_flags(user_flags);
1842 const_cast<::Triangulation<dim, spacedim> &>(
1843 dof_handler.get_triangulation())
1844 .clear_user_flags();
1845
1846
1848 cell = dof_handler.begin_active(),
1849 endc = dof_handler.end();
1850 for (; cell != endc; ++cell)
1851 {
1852 // We only want lines that are locally_relevant
1853 // although it doesn't hurt to have lines that
1854 // are children of ghost cells since there are
1855 // few and we don't have to use them.
1856 if (cell->is_artificial() == false)
1857 {
1858 for (unsigned int l = 0; l < cell->n_lines(); ++l)
1859 if (cell->line(l)->has_children())
1860 for (unsigned int c = 0; c < cell->line(l)->n_children();
1861 ++c)
1862 {
1863 lines_to_parent_lines_map[cell->line(l)->child(c)] =
1864 cell->line(l);
1865 // set flags to know that child
1866 // line has an active parent.
1867 cell->line(l)->child(c)->set_user_flag();
1868 }
1869 }
1870 }
1871 }
1872
1873
1874 // We loop through all cells and add cell to the
1875 // map for the dofs that it immediately touches
1876 // and then account for all the other dofs of
1877 // which it is a part, mainly the ones that must
1878 // be added on account of adaptivity hanging node
1879 // constraints.
1881 cell = dof_handler.begin_active(),
1882 endc = dof_handler.end();
1883 for (; cell != endc; ++cell)
1884 {
1885 // Need to loop through all cells that could
1886 // be in the patch of dofs on locally_owned
1887 // cells including ghost cells
1888 if (cell->is_artificial() == false)
1889 {
1890 const unsigned int n_dofs_per_cell =
1891 cell->get_fe().n_dofs_per_cell();
1892 local_dof_indices.resize(n_dofs_per_cell);
1893
1894 // Take care of adding cell pointer to each
1895 // dofs that exists on cell.
1896 cell->get_dof_indices(local_dof_indices);
1897 for (unsigned int i = 0; i < n_dofs_per_cell; ++i)
1898 dof_to_set_of_cells_map[local_dof_indices[i]].insert(cell);
1899
1900 // In the case of the adjacent cell (over
1901 // faces or edges) being more refined, we
1902 // want to add all of the children to the
1903 // patch since the support function at that
1904 // dof could be non-zero along that entire
1905 // face (or line).
1906
1907 // Take care of dofs on neighbor faces
1908 for (const unsigned int f : cell->face_indices())
1909 {
1910 if (cell->face(f)->has_children())
1911 {
1912 for (unsigned int c = 0; c < cell->face(f)->n_children();
1913 ++c)
1914 {
1915 // Add cell to dofs of all subfaces
1916 //
1917 // *-------------------*----------*---------*
1918 // | | add cell | |
1919 // | |<- to dofs| |
1920 // | |of subface| |
1921 // | cell *----------*---------*
1922 // | | add cell | |
1923 // | |<- to dofs| |
1924 // | |of subface| |
1925 // *-------------------*----------*---------*
1926 //
1927 Assert(cell->face(f)->child(c)->has_children() == false,
1929
1930 const unsigned int n_dofs_per_face =
1931 cell->get_fe().n_dofs_per_face(f, c);
1932 local_face_dof_indices.resize(n_dofs_per_face);
1933
1934 cell->face(f)->child(c)->get_dof_indices(
1935 local_face_dof_indices);
1936 for (unsigned int i = 0; i < n_dofs_per_face; ++i)
1937 dof_to_set_of_cells_map[local_face_dof_indices[i]]
1938 .insert(cell);
1939 }
1940 }
1941 else if ((cell->face(f)->at_boundary() == false) &&
1942 (cell->neighbor_is_coarser(f)))
1943 {
1944 // Add cell to dofs of parent face and all
1945 // child faces of parent face
1946 //
1947 // *-------------------*----------*---------*
1948 // | | | |
1949 // | | cell | |
1950 // | add cell | | |
1951 // | to dofs -> *----------*---------*
1952 // | of parent | add cell | |
1953 // | face |<- to dofs| |
1954 // | |of subface| |
1955 // *-------------------*----------*---------*
1956 //
1957
1958 // Add cell to all dofs of parent face
1959 auto [face_no, subface] =
1960 cell->neighbor_of_coarser_neighbor(f);
1961
1962
1963 const unsigned int n_dofs_per_face =
1964 cell->get_fe().n_dofs_per_face(face_no);
1965 local_face_dof_indices.resize(n_dofs_per_face);
1966
1967 cell->neighbor(f)->face(face_no)->get_dof_indices(
1968 local_face_dof_indices);
1969 for (unsigned int i = 0; i < n_dofs_per_face; ++i)
1970 dof_to_set_of_cells_map[local_face_dof_indices[i]].insert(
1971 cell);
1972
1973 // Add cell to all dofs of children of
1974 // parent face
1975 for (unsigned int c = 0;
1976 c < cell->neighbor(f)->face(face_no)->n_children();
1977 ++c)
1978 {
1979 if (c != subface) // don't repeat work on dofs of
1980 // original cell
1981 {
1982 const unsigned int n_dofs_per_face =
1983 cell->get_fe().n_dofs_per_face(face_no, c);
1984 local_face_dof_indices.resize(n_dofs_per_face);
1985
1986 Assert(cell->neighbor(f)
1987 ->face(face_no)
1988 ->child(c)
1989 ->has_children() == false,
1991 cell->neighbor(f)
1992 ->face(face_no)
1993 ->child(c)
1994 ->get_dof_indices(local_face_dof_indices);
1995 for (unsigned int i = 0; i < n_dofs_per_face; ++i)
1996 dof_to_set_of_cells_map[local_face_dof_indices[i]]
1997 .insert(cell);
1998 }
1999 }
2000 }
2001 }
2002
2003
2004 // If 3d, take care of dofs on lines in the
2005 // same pattern as faces above. That is, if
2006 // a cell's line has children, distribute
2007 // cell to dofs of children of line, and
2008 // if cell's line has an active parent, then
2009 // distribute cell to dofs on parent line
2010 // and dofs on all children of parent line.
2011 if (dim == 3)
2012 {
2013 for (unsigned int l = 0; l < cell->n_lines(); ++l)
2014 {
2015 if (cell->line(l)->has_children())
2016 {
2017 for (unsigned int c = 0;
2018 c < cell->line(l)->n_children();
2019 ++c)
2020 {
2021 Assert(cell->line(l)->child(c)->has_children() ==
2022 false,
2024
2025 // dofs_per_line returns number of dofs
2026 // on line not including the vertices of the line.
2027 const unsigned int n_dofs_per_line =
2028 2 * cell->get_fe().n_dofs_per_vertex() +
2029 cell->get_fe().n_dofs_per_line();
2030 local_line_dof_indices.resize(n_dofs_per_line);
2031
2032 cell->line(l)->child(c)->get_dof_indices(
2033 local_line_dof_indices);
2034 for (unsigned int i = 0; i < n_dofs_per_line; ++i)
2035 dof_to_set_of_cells_map[local_line_dof_indices[i]]
2036 .insert(cell);
2037 }
2038 }
2039 // user flag was set above to denote that
2040 // an active parent line exists so add
2041 // cell to dofs of parent and all it's
2042 // children
2043 else if (cell->line(l)->user_flag_set() == true)
2044 {
2046 parent_line =
2047 lines_to_parent_lines_map[cell->line(l)];
2048 Assert(parent_line->has_children(), ExcInternalError());
2049
2050 // dofs_per_line returns number of dofs
2051 // on line not including the vertices of the line.
2052 const unsigned int n_dofs_per_line =
2053 2 * cell->get_fe().n_dofs_per_vertex() +
2054 cell->get_fe().n_dofs_per_line();
2055 local_line_dof_indices.resize(n_dofs_per_line);
2056
2057 parent_line->get_dof_indices(local_line_dof_indices);
2058 for (unsigned int i = 0; i < n_dofs_per_line; ++i)
2059 dof_to_set_of_cells_map[local_line_dof_indices[i]]
2060 .insert(cell);
2061
2062 for (unsigned int c = 0; c < parent_line->n_children();
2063 ++c)
2064 {
2065 Assert(parent_line->child(c)->has_children() ==
2066 false,
2068
2069 const unsigned int n_dofs_per_line =
2070 2 * cell->get_fe().n_dofs_per_vertex() +
2071 cell->get_fe().n_dofs_per_line();
2072 local_line_dof_indices.resize(n_dofs_per_line);
2073
2074 parent_line->child(c)->get_dof_indices(
2075 local_line_dof_indices);
2076 for (unsigned int i = 0; i < n_dofs_per_line; ++i)
2077 dof_to_set_of_cells_map[local_line_dof_indices[i]]
2078 .insert(cell);
2079 }
2080 }
2081 } // for lines l
2082 } // if dim == 3
2083 } // if cell->is_locally_owned()
2084 } // for cells
2085
2086
2087 if (dim == 3)
2088 {
2089 // finally, restore user flags that were changed above
2090 // to when we constructed the pointers to parent of lines
2091 // Since dof_handler is const, we must leave it unchanged.
2092 const_cast<::Triangulation<dim, spacedim> &>(
2093 dof_handler.get_triangulation())
2094 .load_user_flags(user_flags);
2095 }
2096
2097 // Finally, we copy map of sets to
2098 // map of vectors using the std::vector::assign() function
2099 std::map<
2101 std::vector<typename DoFHandler<dim, spacedim>::active_cell_iterator>>
2102 dof_to_cell_patches;
2103
2104 typename std::map<
2106 std::set<typename DoFHandler<dim, spacedim>::active_cell_iterator>>::
2107 iterator it = dof_to_set_of_cells_map.begin(),
2108 it_end = dof_to_set_of_cells_map.end();
2109 for (; it != it_end; ++it)
2110 dof_to_cell_patches[it->first].assign(it->second.begin(),
2111 it->second.end());
2112
2113 return dof_to_cell_patches;
2114 }
2115
2116 /*
2117 * Internally used in collect_periodic_faces
2118 */
2119 template <typename CellIterator>
2120 void
2122 std::set<std::pair<CellIterator, unsigned int>> &pairs1,
2123 std::set<std::pair<std_cxx20::type_identity_t<CellIterator>, unsigned int>>
2124 &pairs2,
2125 const unsigned int direction,
2126 std::vector<PeriodicFacePair<CellIterator>> &matched_pairs,
2127 const ::Tensor<1, CellIterator::AccessorType::space_dimension>
2128 &offset,
2129 const FullMatrix<double> &matrix,
2130 const double abs_tol = 1e-10)
2131 {
2132 static const int space_dim = CellIterator::AccessorType::space_dimension;
2133 AssertIndexRange(direction, space_dim);
2134
2135 if constexpr (running_in_debug_mode())
2136 {
2137 {
2138 constexpr int dim = CellIterator::AccessorType::dimension;
2139 constexpr int spacedim = CellIterator::AccessorType::space_dimension;
2140 // For parallel::fullydistributed::Triangulation there might be
2141 // unmatched faces on periodic boundaries on the coarse grid. As a
2142 // result this assert is not fulfilled (which is not a bug!). See also
2143 // the discussion in the method collect_periodic_faces.
2144 if (!(((pairs1.size() > 0) &&
2145 (dynamic_cast<const parallel::fullydistributed::
2146 Triangulation<dim, spacedim> *>(
2147 &pairs1.begin()->first->get_triangulation()) != nullptr)) ||
2148 ((pairs2.size() > 0) &&
2149 (dynamic_cast<const parallel::fullydistributed::
2150 Triangulation<dim, spacedim> *>(
2151 &pairs2.begin()->first->get_triangulation()) != nullptr))))
2152 Assert(pairs1.size() == pairs2.size(),
2153 ExcMessage("Unmatched faces on periodic boundaries"));
2154 }
2155 }
2156
2157 unsigned int n_matches = 0;
2158
2159 // Match with a complexity of O(n^2). This could be improved...
2160 using PairIterator =
2161 typename std::set<std::pair<CellIterator, unsigned int>>::const_iterator;
2162 for (PairIterator it1 = pairs1.begin(); it1 != pairs1.end(); ++it1)
2163 {
2164 for (PairIterator it2 = pairs2.begin(); it2 != pairs2.end(); ++it2)
2165 {
2166 const CellIterator cell1 = it1->first;
2167 const CellIterator cell2 = it2->first;
2168 const unsigned int face_idx1 = it1->second;
2169 const unsigned int face_idx2 = it2->second;
2170 if (const std::optional<types::geometric_orientation> orientation =
2171 GridTools::orthogonal_equality(cell1->face(face_idx1),
2172 cell2->face(face_idx2),
2173 direction,
2174 offset,
2175 matrix,
2176 abs_tol))
2177 {
2178 // We have a match, so insert the matching pairs and
2179 // remove the matched cell in pairs2 to speed up the
2180 // matching:
2181 const PeriodicFacePair<CellIterator> matched_face = {
2182 {cell1, cell2},
2183 {face_idx1, face_idx2},
2184 orientation.value(),
2185 matrix};
2186 matched_pairs.push_back(matched_face);
2187 pairs2.erase(it2);
2188 ++n_matches;
2189 break;
2190 }
2191 }
2192 }
2193
2194 // Assure that all faces are matched if
2195 // parallel::fullydistributed::Triangulation is not used. This is related to
2196 // the fact that the faces might not be successfully matched on the coarse
2197 // grid (not a bug!). See also the comment above and in the method
2198 // collect_periodic_faces.
2199 {
2200 constexpr int dim = CellIterator::AccessorType::dimension;
2201 constexpr int spacedim = CellIterator::AccessorType::space_dimension;
2202 if (!(((pairs1.size() > 0) &&
2203 (dynamic_cast<const parallel::fullydistributed::
2204 Triangulation<dim, spacedim> *>(
2205 &pairs1.begin()->first->get_triangulation()) != nullptr)) ||
2206 ((pairs2.size() > 0) &&
2207 (dynamic_cast<
2209 *>(&pairs2.begin()->first->get_triangulation()) != nullptr))))
2210 AssertThrow(n_matches == pairs1.size() && pairs2.empty(),
2211 ExcMessage("Unmatched faces on periodic boundaries"));
2212 }
2213 }
2214
2215
2216
2217 template <typename MeshType>
2220 const MeshType &mesh,
2221 const types::boundary_id b_id,
2222 const unsigned int direction,
2223 std::vector<PeriodicFacePair<typename MeshType::cell_iterator>>
2224 &matched_pairs,
2225 const Tensor<1, MeshType::space_dimension> &offset,
2226 const FullMatrix<double> &matrix,
2227 const double abs_tol)
2228 {
2229 static const int dim = MeshType::dimension;
2230 static const int space_dim = MeshType::space_dimension;
2231 AssertIndexRange(direction, space_dim);
2232 Assert(dim == space_dim, ExcNotImplemented());
2233
2234 // Loop over all cells on the highest level and collect all boundary
2235 // faces 2*direction and 2*direction*1:
2236
2237 std::set<std::pair<typename MeshType::cell_iterator, unsigned int>> pairs1;
2238 std::set<std::pair<typename MeshType::cell_iterator, unsigned int>> pairs2;
2239
2240 for (typename MeshType::cell_iterator cell = mesh.begin(0);
2241 cell != mesh.end(0);
2242 ++cell)
2243 {
2244 const typename MeshType::face_iterator face_1 =
2245 cell->face(2 * direction);
2246 const typename MeshType::face_iterator face_2 =
2247 cell->face(2 * direction + 1);
2248
2249 if (face_1->at_boundary() && face_1->boundary_id() == b_id)
2250 {
2251 const std::pair<typename MeshType::cell_iterator, unsigned int>
2252 pair1 = std::make_pair(cell, 2 * direction);
2253 pairs1.insert(pair1);
2254 }
2255
2256 if (face_2->at_boundary() && face_2->boundary_id() == b_id)
2257 {
2258 const std::pair<typename MeshType::cell_iterator, unsigned int>
2259 pair2 = std::make_pair(cell, 2 * direction + 1);
2260 pairs2.insert(pair2);
2261 }
2262 }
2263
2264 Assert(pairs1.size() == pairs2.size(),
2265 ExcMessage("Unmatched faces on periodic boundaries"));
2266
2267 Assert(pairs1.size() > 0,
2268 ExcMessage("No new periodic face pairs have been found. "
2269 "Are you sure that you've selected the correct boundary "
2270 "id's and that the coarsest level mesh is colorized?"));
2271
2272 [[maybe_unused]] const unsigned int size_old = matched_pairs.size();
2273
2274 // and call match_periodic_face_pairs that does the actual matching:
2276 pairs1, pairs2, direction, matched_pairs, offset, matrix, abs_tol);
2277
2278 if constexpr (running_in_debug_mode())
2279 {
2280 // check for standard orientation
2281 const unsigned int size_new = matched_pairs.size();
2282 for (unsigned int i = size_old; i < size_new; ++i)
2283 {
2284 Assert(matched_pairs[i].orientation ==
2286 ExcMessage(
2287 "Found a face match with non standard orientation. "
2288 "This function is only suitable for meshes with cells "
2289 "in default orientation"));
2290 }
2291 }
2292 }
2293
2294
2295
2296 template <typename MeshType>
2299 const MeshType &mesh,
2300 const types::boundary_id b_id1,
2301 const types::boundary_id b_id2,
2302 const unsigned int direction,
2303 std::vector<PeriodicFacePair<typename MeshType::cell_iterator>>
2304 &matched_pairs,
2305 const Tensor<1, MeshType::space_dimension> &offset,
2306 const FullMatrix<double> &matrix,
2307 const double abs_tol)
2308 {
2309 static const int dim = MeshType::dimension;
2310 static const int space_dim = MeshType::space_dimension;
2311 AssertIndexRange(direction, space_dim);
2312
2313 // Loop over all cells on the highest level and collect all boundary
2314 // faces belonging to b_id1 and b_id2:
2315
2316 std::set<std::pair<typename MeshType::cell_iterator, unsigned int>> pairs1;
2317 std::set<std::pair<typename MeshType::cell_iterator, unsigned int>> pairs2;
2318
2319 for (typename MeshType::cell_iterator cell = mesh.begin(0);
2320 cell != mesh.end(0);
2321 ++cell)
2322 {
2323 for (const unsigned int i : cell->face_indices())
2324 {
2325 const typename MeshType::face_iterator face = cell->face(i);
2326 if (face->at_boundary() && face->boundary_id() == b_id1)
2327 {
2328 const std::pair<typename MeshType::cell_iterator, unsigned int>
2329 pair1 = std::make_pair(cell, i);
2330 pairs1.insert(pair1);
2331 }
2332
2333 if (face->at_boundary() && face->boundary_id() == b_id2)
2334 {
2335 const std::pair<typename MeshType::cell_iterator, unsigned int>
2336 pair2 = std::make_pair(cell, i);
2337 pairs2.insert(pair2);
2338 }
2339 }
2340 }
2341
2342 // Assure that all faces are matched on the coarse grid. This requirement
2343 // can only fulfilled if a process owns the complete coarse grid. This is
2344 // not the case for a parallel::fullydistributed::Triangulation, i.e., this
2345 // requirement has not to be met (consider faces on the outside of a
2346 // ghost cell that are periodic but for which the ghost neighbor doesn't
2347 // exist).
2348 if (!(((pairs1.size() > 0) &&
2349 (dynamic_cast<
2351 *>(&pairs1.begin()->first->get_triangulation()) != nullptr)) ||
2352 ((pairs2.size() > 0) &&
2353 (dynamic_cast<
2355 *>(&pairs2.begin()->first->get_triangulation()) != nullptr))))
2356 Assert(pairs1.size() == pairs2.size(),
2357 ExcMessage("Unmatched faces on periodic boundaries"));
2358
2359 Assert(
2360 (pairs1.size() > 0 ||
2361 (dynamic_cast<
2363 &mesh.begin()->get_triangulation()) != nullptr)),
2364 ExcMessage("No new periodic face pairs have been found. "
2365 "Are you sure that you've selected the correct boundary "
2366 "id's and that the coarsest level mesh is colorized?"));
2367
2368 // and call match_periodic_face_pairs that does the actual matching:
2370 pairs1, pairs2, direction, matched_pairs, offset, matrix, abs_tol);
2371 }
2372
2373
2374
2375 /*
2376 * Internally used in orthogonal_equality
2377 *
2378 * An orthogonal equality test for points:
2379 *
2380 * point1 and point2 are considered equal, if
2381 * matrix.point1 + offset - point2
2382 * is parallel to the unit vector in <direction>
2383 */
2384 template <int spacedim>
2385 bool
2387 const Point<spacedim> &point2,
2388 const unsigned int direction,
2389 const Tensor<1, spacedim> &offset,
2390 const FullMatrix<double> &matrix,
2391 const double abs_tol = 1e-10)
2392 {
2393 AssertIndexRange(direction, spacedim);
2394
2395 Assert(matrix.m() == matrix.n(), ExcInternalError());
2396
2397 Point<spacedim> distance;
2398
2399 if (matrix.m() == spacedim)
2400 for (unsigned int i = 0; i < spacedim; ++i)
2401 for (unsigned int j = 0; j < spacedim; ++j)
2402 distance[i] += matrix(i, j) * point1[j];
2403 else
2404 distance = point1;
2405
2406 distance += offset - point2;
2407
2408 for (unsigned int i = 0; i < spacedim; ++i)
2409 {
2410 // Only compare coordinate-components != direction:
2411 if (i == direction)
2412 continue;
2413
2414 if (std::abs(distance[i]) > abs_tol)
2415 return false;
2416 }
2417
2418 return true;
2419 }
2420
2421
2422
2423 template <typename FaceIterator>
2424 std::optional<types::geometric_orientation>
2426 const FaceIterator &face1,
2427 const FaceIterator &face2,
2428 const unsigned int direction,
2430 const FullMatrix<double> &matrix,
2431 const double abs_tol)
2432 {
2433 Assert(matrix.m() == matrix.n(),
2434 ExcMessage("The supplied matrix must be a square matrix"));
2435 Assert(face1->reference_cell() == face2->reference_cell(),
2436 ExcMessage(
2437 "The faces to be matched must have the same reference cell."));
2438
2439 // Do a full matching of the face vertices:
2440 AssertDimension(face1->n_vertices(), face2->n_vertices());
2441
2442 std::vector<unsigned int> face1_vertices(face1->n_vertices(),
2444 face2_vertices(face2->n_vertices(), numbers::invalid_unsigned_int);
2445
2446 std::set<unsigned int> face2_vertices_set;
2447 for (unsigned int i = 0; i < face1->n_vertices(); ++i)
2448 face2_vertices_set.insert(i);
2449
2450 for (unsigned int i = 0; i < face1->n_vertices(); ++i)
2451 {
2452 for (auto it = face2_vertices_set.begin();
2453 it != face2_vertices_set.end();
2454 ++it)
2455 {
2456 if (orthogonal_equality(face1->vertex(i),
2457 face2->vertex(*it),
2458 direction,
2459 offset,
2460 matrix,
2461 abs_tol))
2462 {
2463 face1_vertices[i] = *it;
2464 face2_vertices[i] = i;
2465 face2_vertices_set.erase(it);
2466 break; // jump out of the innermost loop
2467 }
2468 }
2469 }
2470
2471 if (face2_vertices_set.empty())
2472 {
2473 // Just to be sure, did we fill both arrays with sensible data?
2474 Assert(face1_vertices.end() ==
2475 std::find(face1_vertices.begin(),
2476 face1_vertices.begin() + face1->n_vertices(),
2479 Assert(face2_vertices.end() ==
2480 std::find(face2_vertices.begin(),
2481 face2_vertices.begin() + face1->n_vertices(),
2484
2485 const auto reference_cell = face1->reference_cell();
2486 // We want the relative orientation of face1 with respect to face2 so
2487 // the order is flipped here:
2488 return std::make_optional(reference_cell.get_combined_orientation(
2489 make_array_view(face2_vertices.cbegin(),
2490 face2_vertices.cbegin() + face2->n_vertices()),
2491 make_array_view(face1_vertices.cbegin(),
2492 face1_vertices.cbegin() + face1->n_vertices())));
2493 }
2494 else
2495 return std::nullopt;
2496 }
2497} // namespace GridTools
2498
2499
2500#include "grid/grid_tools_dof_handlers.inst"
2501
2502
*  x_component_mask set(0, true)
*  *  const_iterator()=default
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
cell_iterator end() const
const hp::FECollection< dim, spacedim > & get_fe_collection() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const Triangulation< dim, spacedim > & get_triangulation() const
active_cell_iterator begin_active(const unsigned int level=0) const
unsigned int n_dofs_per_vertex() const
unsigned int n_dofs_per_cell() const
unsigned int n_dofs_per_line() const
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
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
Definition point.h:111
constexpr numbers::NumberTraits< Number >::real_type distance_square(const Point< dim, Number > &p) const
virtual void clear()
cell_iterator begin(const unsigned int level=0) 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 save_user_flags(std::ostream &out) const
const std::vector< Point< spacedim > > & get_vertices() const
cell_iterator end() const
void clear_user_flags()
virtual void execute_coarsening_and_refinement()
unsigned int n_cells() const
const std::vector< bool > & get_used_vertices() const
Triangulation< dim, spacedim > & get_triangulation()
unsigned int size() const
Definition collection.h:314
#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
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
unsigned int level
Definition grid_out.cc:4642
AdjacentCell adjacent_cells[2]
unsigned int vertex_indices[2]
IteratorRange< active_cell_iterator > active_cell_iterators() const
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcVertexNotUsed(unsigned int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
typename ActiveSelector::line_iterator line_iterator
typename ActiveSelector::active_cell_iterator active_cell_iterator
const Mapping< dim, spacedim > & get_default_linear_mapping(const Triangulation< dim, spacedim > &triangulation)
Definition mapping.cc:314
std::vector< typename Container::cell_iterator > get_cells_at_coarsest_common_level(const std::vector< typename Container::active_cell_iterator > &patch_cells)
void collect_periodic_faces(const MeshType &mesh, const types::boundary_id b_id1, const types::boundary_id b_id2, const unsigned int direction, std::vector< PeriodicFacePair< typename MeshType::cell_iterator > > &matched_pairs, const Tensor< 1, MeshType::space_dimension > &offset=::Tensor< 1, MeshType::space_dimension >(), const FullMatrix< double > &matrix=FullMatrix< double >(), const double abs_tol=1e-10)
unsigned int find_closest_vertex(const std::map< unsigned int, Point< spacedim > > &vertices, const Point< spacedim > &p)
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::list< std::pair< typename MeshType::cell_iterator, typename MeshType::cell_iterator > > get_finest_common_cells(const MeshType &mesh_1, const MeshType &mesh_2)
std::vector< typename MeshType::active_cell_iterator > find_cells_adjacent_to_vertex(const MeshType &container, const unsigned int vertex_index)
std::vector< typename MeshType::active_cell_iterator > compute_active_cell_halo_layer(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate)
std::vector< typename MeshType::active_cell_iterator > compute_active_cell_layer_within_distance(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate, const double layer_thickness)
std::vector< typename MeshType::active_cell_iterator > compute_ghost_cell_halo_layer(const MeshType &mesh)
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)
void match_periodic_face_pairs(std::set< std::pair< CellIterator, unsigned int > > &pairs1, std::set< std::pair< std_cxx20::type_identity_t< CellIterator >, unsigned int > > &pairs2, const unsigned int direction, std::vector< PeriodicFacePair< CellIterator > > &matched_pairs, const ::Tensor< 1, CellIterator::AccessorType::space_dimension > &offset, const FullMatrix< double > &matrix, const double abs_tol=1e-10)
std::map< types::global_dof_index, std::vector< typename DoFHandler< dim, spacedim >::active_cell_iterator > > get_dof_to_support_patch_map(DoFHandler< dim, spacedim > &dof_handler)
std::vector< typename MeshType::cell_iterator > compute_cell_halo_layer_on_level(const MeshType &mesh, const std::function< bool(const typename MeshType::cell_iterator &)> &predicate, const unsigned int level)
std::vector< typename MeshType::active_cell_iterator > compute_ghost_cell_layer_within_distance(const MeshType &mesh, const double layer_thickness)
bool have_same_coarse_mesh(const Triangulation< dim, spacedim > &mesh_1, const Triangulation< dim, spacedim > &mesh_2)
std::vector< typename MeshType::active_cell_iterator > get_patch_around_cell(const typename MeshType::active_cell_iterator &cell)
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)
void build_triangulation_from_patch(const std::vector< typename Container::active_cell_iterator > &patch, Triangulation< Container::dimension, Container::space_dimension > &local_triangulation, std::map< typename Triangulation< Container::dimension, Container::space_dimension >::active_cell_iterator, typename Container::active_cell_iterator > &patch_to_global_tria_map)
std::optional< types::geometric_orientation > orthogonal_equality(const FaceIterator &face1, const FaceIterator &face2, const unsigned int direction, const Tensor< 1, FaceIterator::AccessorType::space_dimension > &offset=Tensor< 1, FaceIterator::AccessorType::space_dimension >(), const FullMatrix< double > &matrix=FullMatrix< double >(), const double abs_tol=1e-10)
BoundingBox< spacedim > compute_bounding_box(const Triangulation< dim, spacedim > &triangulation)
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 >()))
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
typename type_identity< T >::type type_identity_t
Definition type_traits.h:93
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 > abs(const ::VectorizedArray< Number, width > &)
Definition types.h:30
unsigned int global_dof_index
Definition types.h:92