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