Reference documentation for deal.II version 9.1.0-pre
grid_tools.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2001 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/mpi.h>
17 #include <deal.II/base/mpi.templates.h>
18 #include <deal.II/base/quadrature_lib.h>
19 #include <deal.II/base/thread_management.h>
20 
21 #include <deal.II/distributed/shared_tria.h>
22 #include <deal.II/distributed/tria.h>
23 
24 #include <deal.II/dofs/dof_accessor.h>
25 #include <deal.II/dofs/dof_handler.h>
26 #include <deal.II/dofs/dof_tools.h>
27 
28 #include <deal.II/fe/fe_nothing.h>
29 #include <deal.II/fe/fe_q.h>
30 #include <deal.II/fe/fe_values.h>
31 #include <deal.II/fe/mapping_q.h>
32 #include <deal.II/fe/mapping_q1.h>
33 #include <deal.II/fe/mapping_q_generic.h>
34 
35 #include <deal.II/grid/filtered_iterator.h>
36 #include <deal.II/grid/grid_reordering.h>
37 #include <deal.II/grid/grid_tools.h>
38 #include <deal.II/grid/grid_tools_cache.h>
39 #include <deal.II/grid/manifold.h>
40 #include <deal.II/grid/tria.h>
41 #include <deal.II/grid/tria_accessor.h>
42 #include <deal.II/grid/tria_iterator.h>
43 
44 #include <deal.II/lac/dynamic_sparsity_pattern.h>
45 #include <deal.II/lac/filtered_matrix.h>
46 #include <deal.II/lac/precondition.h>
47 #include <deal.II/lac/solver_cg.h>
48 #include <deal.II/lac/sparse_matrix.h>
49 #include <deal.II/lac/sparsity_pattern.h>
50 #include <deal.II/lac/sparsity_tools.h>
51 #include <deal.II/lac/vector.h>
52 #include <deal.II/lac/vector_memory.h>
53 
54 #include <deal.II/numerics/matrix_tools.h>
55 
56 #include <boost/random/mersenne_twister.hpp>
57 #include <boost/random/uniform_real_distribution.hpp>
58 
59 #include <array>
60 #include <cmath>
61 #include <iostream>
62 #include <list>
63 #include <numeric>
64 #include <set>
65 #include <tuple>
66 #include <unordered_map>
67 
68 DEAL_II_NAMESPACE_OPEN
69 
70 
71 namespace GridTools
72 {
73  template <int dim, int spacedim>
74  double
76  {
77  // we can't deal with distributed meshes since we don't have all
78  // vertices locally. there is one exception, however: if the mesh has
79  // never been refined. the way to test this is not to ask
80  // tria.n_levels()==1, since this is something that can happen on one
81  // processor without being true on all. however, we can ask for the
82  // global number of active cells and use that
83 #if defined(DEAL_II_WITH_P4EST) && defined(DEBUG)
85  dynamic_cast<
87  Assert(p_tria->n_global_active_cells() == tria.n_cells(0),
89 #endif
90 
91  // the algorithm used simply traverses all cells and picks out the
92  // boundary vertices. it may or may not be faster to simply get all
93  // vectors, don't mark boundary vertices, and compute the distances
94  // thereof, but at least as the mesh is refined, it seems better to
95  // first mark boundary nodes, as marking is O(N) in the number of
96  // cells/vertices, while computing the maximal distance is O(N*N)
97  const std::vector<Point<spacedim>> &vertices = tria.get_vertices();
98  std::vector<bool> boundary_vertices(vertices.size(), false);
99 
101  tria.begin_active();
103  tria.end();
104  for (; cell != endc; ++cell)
105  for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell;
106  ++face)
107  if (cell->face(face)->at_boundary())
108  for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_face;
109  ++i)
110  boundary_vertices[cell->face(face)->vertex_index(i)] = true;
111 
112  // now traverse the list of boundary vertices and check distances.
113  // since distances are symmetric, we only have to check one half
114  double max_distance_sqr = 0;
115  std::vector<bool>::const_iterator pi = boundary_vertices.begin();
116  const unsigned int N = boundary_vertices.size();
117  for (unsigned int i = 0; i < N; ++i, ++pi)
118  {
119  std::vector<bool>::const_iterator pj = pi + 1;
120  for (unsigned int j = i + 1; j < N; ++j, ++pj)
121  if ((*pi == true) && (*pj == true) &&
122  ((vertices[i] - vertices[j]).norm_square() > max_distance_sqr))
123  max_distance_sqr = (vertices[i] - vertices[j]).norm_square();
124  };
125 
126  return std::sqrt(max_distance_sqr);
127  }
128 
129 
130 
131  template <int dim, int spacedim>
132  double
133  volume(const Triangulation<dim, spacedim> &triangulation,
134  const Mapping<dim, spacedim> & mapping)
135  {
136  // get the degree of the mapping if possible. if not, just assume 1
137  unsigned int mapping_degree = 1;
138  if (const auto *p =
139  dynamic_cast<const MappingQGeneric<dim, spacedim> *>(&mapping))
140  mapping_degree = p->get_degree();
141  else if (const auto *p =
142  dynamic_cast<const MappingQ<dim, spacedim> *>(&mapping))
143  mapping_degree = p->get_degree();
144 
145  // then initialize an appropriate quadrature formula
146  const QGauss<dim> quadrature_formula(mapping_degree + 1);
147  const unsigned int n_q_points = quadrature_formula.size();
148 
149  // we really want the JxW values from the FEValues object, but it
150  // wants a finite element. create a cheap element as a dummy
151  // element
152  FE_Nothing<dim, spacedim> dummy_fe;
153  FEValues<dim, spacedim> fe_values(mapping,
154  dummy_fe,
155  quadrature_formula,
157 
159  cell = triangulation.begin_active(),
160  endc = triangulation.end();
161 
162  double local_volume = 0;
163 
164  // compute the integral quantities by quadrature
165  for (; cell != endc; ++cell)
166  if (cell->is_locally_owned())
167  {
168  fe_values.reinit(cell);
169  for (unsigned int q = 0; q < n_q_points; ++q)
170  local_volume += fe_values.JxW(q);
171  }
172 
173  double global_volume = 0;
174 
175 #ifdef DEAL_II_WITH_MPI
176  if (const parallel::Triangulation<dim, spacedim> *p_tria =
177  dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
178  &triangulation))
179  global_volume =
180  Utilities::MPI::sum(local_volume, p_tria->get_communicator());
181  else
182 #endif
183  global_volume = local_volume;
184 
185  return global_volume;
186  }
187 
188 
189 
190  template <>
191  double
192  cell_measure<1>(
193  const std::vector<Point<1>> &all_vertices,
194  const unsigned int (&vertex_indices)[GeometryInfo<1>::vertices_per_cell])
195  {
196  return all_vertices[vertex_indices[1]][0] -
197  all_vertices[vertex_indices[0]][0];
198  }
199 
200 
201 
202  template <>
203  double
204  cell_measure<3>(
205  const std::vector<Point<3>> &all_vertices,
206  const unsigned int (&vertex_indices)[GeometryInfo<3>::vertices_per_cell])
207  {
208  // note that this is the
209  // cell_measure based on the new
210  // deal.II numbering. When called
211  // from inside GridReordering make
212  // sure that you reorder the
213  // vertex_indices before
214  const double x[8] = {all_vertices[vertex_indices[0]](0),
215  all_vertices[vertex_indices[1]](0),
216  all_vertices[vertex_indices[2]](0),
217  all_vertices[vertex_indices[3]](0),
218  all_vertices[vertex_indices[4]](0),
219  all_vertices[vertex_indices[5]](0),
220  all_vertices[vertex_indices[6]](0),
221  all_vertices[vertex_indices[7]](0)};
222  const double y[8] = {all_vertices[vertex_indices[0]](1),
223  all_vertices[vertex_indices[1]](1),
224  all_vertices[vertex_indices[2]](1),
225  all_vertices[vertex_indices[3]](1),
226  all_vertices[vertex_indices[4]](1),
227  all_vertices[vertex_indices[5]](1),
228  all_vertices[vertex_indices[6]](1),
229  all_vertices[vertex_indices[7]](1)};
230  const double z[8] = {all_vertices[vertex_indices[0]](2),
231  all_vertices[vertex_indices[1]](2),
232  all_vertices[vertex_indices[2]](2),
233  all_vertices[vertex_indices[3]](2),
234  all_vertices[vertex_indices[4]](2),
235  all_vertices[vertex_indices[5]](2),
236  all_vertices[vertex_indices[6]](2),
237  all_vertices[vertex_indices[7]](2)};
238 
239  /*
240  This is the same Maple script as in the barycenter method above
241  except of that here the shape functions tphi[0]-tphi[7] are ordered
242  according to the lexicographic numbering.
243 
244  x := array(0..7):
245  y := array(0..7):
246  z := array(0..7):
247  tphi[0] := (1-xi)*(1-eta)*(1-zeta):
248  tphi[1] := xi*(1-eta)*(1-zeta):
249  tphi[2] := (1-xi)* eta*(1-zeta):
250  tphi[3] := xi* eta*(1-zeta):
251  tphi[4] := (1-xi)*(1-eta)*zeta:
252  tphi[5] := xi*(1-eta)*zeta:
253  tphi[6] := (1-xi)* eta*zeta:
254  tphi[7] := xi* eta*zeta:
255  x_real := sum(x[s]*tphi[s], s=0..7):
256  y_real := sum(y[s]*tphi[s], s=0..7):
257  z_real := sum(z[s]*tphi[s], s=0..7):
258  with (linalg):
259  J := matrix(3,3, [[diff(x_real, xi), diff(x_real, eta), diff(x_real,
260  zeta)], [diff(y_real, xi), diff(y_real, eta), diff(y_real, zeta)],
261  [diff(z_real, xi), diff(z_real, eta), diff(z_real, zeta)]]):
262  detJ := det (J):
263 
264  measure := simplify ( int ( int ( int (detJ, xi=0..1), eta=0..1),
265  zeta=0..1)):
266 
267  readlib(C):
268 
269  C(measure, optimized);
270 
271  The C code produced by this maple script is further optimized by
272  hand. In particular, division by 12 is performed only once, not
273  hundred of times.
274  */
275 
276  const double t3 = y[3] * x[2];
277  const double t5 = z[1] * x[5];
278  const double t9 = z[3] * x[2];
279  const double t11 = x[1] * y[0];
280  const double t14 = x[4] * y[0];
281  const double t18 = x[5] * y[7];
282  const double t20 = y[1] * x[3];
283  const double t22 = y[5] * x[4];
284  const double t26 = z[7] * x[6];
285  const double t28 = x[0] * y[4];
286  const double t34 =
287  z[3] * x[1] * y[2] + t3 * z[1] - t5 * y[7] + y[7] * x[4] * z[6] +
288  t9 * y[6] - t11 * z[4] - t5 * y[3] - t14 * z[2] + z[1] * x[4] * y[0] -
289  t18 * z[3] + t20 * z[0] - t22 * z[0] - y[0] * x[5] * z[4] - t26 * y[3] +
290  t28 * z[2] - t9 * y[1] - y[1] * x[4] * z[0] - t11 * z[5];
291  const double t37 = y[1] * x[0];
292  const double t44 = x[1] * y[5];
293  const double t46 = z[1] * x[0];
294  const double t49 = x[0] * y[2];
295  const double t52 = y[5] * x[7];
296  const double t54 = x[3] * y[7];
297  const double t56 = x[2] * z[0];
298  const double t58 = x[3] * y[2];
299  const double t64 = -x[6] * y[4] * z[2] - t37 * z[2] + t18 * z[6] -
300  x[3] * y[6] * z[2] + t11 * z[2] + t5 * y[0] +
301  t44 * z[4] - t46 * y[4] - t20 * z[7] - t49 * z[6] -
302  t22 * z[1] + t52 * z[3] - t54 * z[2] - t56 * y[4] -
303  t58 * z[0] + y[1] * x[2] * z[0] + t9 * y[7] + t37 * z[4];
304  const double t66 = x[1] * y[7];
305  const double t68 = y[0] * x[6];
306  const double t70 = x[7] * y[6];
307  const double t73 = z[5] * x[4];
308  const double t76 = x[6] * y[7];
309  const double t90 = x[4] * z[0];
310  const double t92 = x[1] * y[3];
311  const double t95 = -t66 * z[3] - t68 * z[2] - t70 * z[2] + t26 * y[5] -
312  t73 * y[6] - t14 * z[6] + t76 * z[2] - t3 * z[6] +
313  x[6] * y[2] * z[4] - z[3] * x[6] * y[2] + t26 * y[4] -
314  t44 * z[3] - x[1] * y[2] * z[0] + x[5] * y[6] * z[4] +
315  t54 * z[5] + t90 * y[2] - t92 * z[2] + t46 * y[2];
316  const double t102 = x[2] * y[0];
317  const double t107 = y[3] * x[7];
318  const double t114 = x[0] * y[6];
319  const double t125 =
320  y[0] * x[3] * z[2] - z[7] * x[5] * y[6] - x[2] * y[6] * z[4] +
321  t102 * z[6] - t52 * z[6] + x[2] * y[4] * z[6] - t107 * z[5] - t54 * z[6] +
322  t58 * z[6] - x[7] * y[4] * z[6] + t37 * z[5] - t114 * z[4] + t102 * z[4] -
323  z[1] * x[2] * y[0] + t28 * z[6] - y[5] * x[6] * z[4] -
324  z[5] * x[1] * y[4] - t73 * y[7];
325  const double t129 = z[0] * x[6];
326  const double t133 = y[1] * x[7];
327  const double t145 = y[1] * x[5];
328  const double t156 = t90 * y[6] - t129 * y[4] + z[7] * x[2] * y[6] -
329  t133 * z[5] + x[5] * y[3] * z[7] - t26 * y[2] -
330  t70 * z[3] + t46 * y[3] + z[5] * x[7] * y[4] +
331  z[7] * x[3] * y[6] - t49 * z[4] + t145 * z[7] -
332  x[2] * y[7] * z[6] + t70 * z[5] + t66 * z[5] -
333  z[7] * x[4] * y[6] + t18 * z[4] + x[1] * y[4] * z[0];
334  const double t160 = x[5] * y[4];
335  const double t165 = z[1] * x[7];
336  const double t178 = z[1] * x[3];
337  const double t181 =
338  t107 * z[6] + t22 * z[7] + t76 * z[3] + t160 * z[1] - x[4] * y[2] * z[6] +
339  t70 * z[4] + t165 * y[5] + x[7] * y[2] * z[6] - t76 * z[5] - t76 * z[4] +
340  t133 * z[3] - t58 * z[1] + y[5] * x[0] * z[4] + t114 * z[2] - t3 * z[7] +
341  t20 * z[2] + t178 * y[7] + t129 * y[2];
342  const double t207 = t92 * z[7] + t22 * z[6] + z[3] * x[0] * y[2] -
343  x[0] * y[3] * z[2] - z[3] * x[7] * y[2] - t165 * y[3] -
344  t9 * y[0] + t58 * z[7] + y[3] * x[6] * z[2] +
345  t107 * z[2] + t73 * y[0] - x[3] * y[5] * z[7] +
346  t3 * z[0] - t56 * y[6] - z[5] * x[0] * y[4] +
347  t73 * y[1] - t160 * z[6] + t160 * z[0];
348  const double t228 = -t44 * z[7] + z[5] * x[6] * y[4] - t52 * z[4] -
349  t145 * z[4] + t68 * z[4] + t92 * z[5] - t92 * z[0] +
350  t11 * z[3] + t44 * z[0] + t178 * y[5] - t46 * y[5] -
351  t178 * y[0] - t145 * z[0] - t20 * z[5] - t37 * z[3] -
352  t160 * z[7] + t145 * z[3] + x[4] * y[6] * z[2];
353 
354  return (t34 + t64 + t95 + t125 + t156 + t181 + t207 + t228) / 12.;
355  }
356 
357 
358 
359  template <>
360  double
361  cell_measure<2>(
362  const std::vector<Point<2>> &all_vertices,
363  const unsigned int (&vertex_indices)[GeometryInfo<2>::vertices_per_cell])
364  {
365  /*
366  Get the computation of the measure by this little Maple script. We
367  use the blinear mapping of the unit quad to the real quad. However,
368  every transformation mapping the unit faces to straight lines should
369  do.
370 
371  Remember that the area of the quad is given by
372  \int_K 1 dx dy = \int_{\hat K} |det J| d(xi) d(eta)
373 
374  # x and y are arrays holding the x- and y-values of the four vertices
375  # of this cell in real space.
376  x := array(0..3);
377  y := array(0..3);
378  z := array(0..3);
379  tphi[0] := (1-xi)*(1-eta):
380  tphi[1] := xi*(1-eta):
381  tphi[2] := (1-xi)*eta:
382  tphi[3] := xi*eta:
383  x_real := sum(x[s]*tphi[s], s=0..3):
384  y_real := sum(y[s]*tphi[s], s=0..3):
385  z_real := sum(z[s]*tphi[s], s=0..3):
386 
387  Jxi := <diff(x_real,xi) | diff(y_real,xi) | diff(z_real,xi)>;
388  Jeta := <diff(x_real,eta)| diff(y_real,eta)| diff(z_real,eta)>;
389  with(VectorCalculus):
390  J := CrossProduct(Jxi, Jeta);
391  detJ := sqrt(J[1]^2 + J[2]^2 +J[3]^2);
392 
393  # measure := evalf (Int (Int (detJ, xi=0..1, method = _NCrule ) ,
394  eta=0..1, method = _NCrule ) ): # readlib(C):
395 
396  # C(measure, optimized);
397 
398  additional optimizaton: divide by 2 only one time
399  */
400 
401  const double x[4] = {all_vertices[vertex_indices[0]](0),
402  all_vertices[vertex_indices[1]](0),
403  all_vertices[vertex_indices[2]](0),
404  all_vertices[vertex_indices[3]](0)};
405 
406  const double y[4] = {all_vertices[vertex_indices[0]](1),
407  all_vertices[vertex_indices[1]](1),
408  all_vertices[vertex_indices[2]](1),
409  all_vertices[vertex_indices[3]](1)};
410 
411  return (-x[1] * y[0] + x[1] * y[3] + y[0] * x[2] + x[0] * y[1] -
412  x[0] * y[2] - y[1] * x[3] - x[2] * y[3] + x[3] * y[2]) /
413  2;
414  }
415 
416 
417 
418  template <int dim, int spacedim>
421  {
422  using iterator =
424  const auto predicate = [](const iterator &) { return true; };
425 
426  return compute_bounding_box(
427  tria, std::function<bool(const iterator &)>(predicate));
428  }
429 
430 
431 
432  template <int dim, int spacedim>
433  void
434  delete_unused_vertices(std::vector<Point<spacedim>> &vertices,
435  std::vector<CellData<dim>> & cells,
436  SubCellData & subcelldata)
437  {
438  Assert(
439  subcelldata.check_consistency(dim),
440  ExcMessage(
441  "Invalid SubCellData supplied according to ::check_consistency(). "
442  "This is caused by data containing objects for the wrong dimension."));
443 
444  // first check which vertices are actually used
445  std::vector<bool> vertex_used(vertices.size(), false);
446  for (unsigned int c = 0; c < cells.size(); ++c)
447  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
448  {
449  Assert(cells[c].vertices[v] < vertices.size(),
450  ExcMessage("Invalid vertex index encountered! cells[" +
451  Utilities::int_to_string(c) + "].vertices[" +
452  Utilities::int_to_string(v) + "]=" +
453  Utilities::int_to_string(cells[c].vertices[v]) +
454  " is invalid, because only " +
455  Utilities::int_to_string(vertices.size()) +
456  " vertices were supplied."));
457  vertex_used[cells[c].vertices[v]] = true;
458  }
459 
460 
461  // then renumber the vertices that are actually used in the same order as
462  // they were beforehand
463  const unsigned int invalid_vertex = numbers::invalid_unsigned_int;
464  std::vector<unsigned int> new_vertex_numbers(vertices.size(),
465  invalid_vertex);
466  unsigned int next_free_number = 0;
467  for (unsigned int i = 0; i < vertices.size(); ++i)
468  if (vertex_used[i] == true)
469  {
470  new_vertex_numbers[i] = next_free_number;
471  ++next_free_number;
472  }
473 
474  // next replace old vertex numbers by the new ones
475  for (unsigned int c = 0; c < cells.size(); ++c)
476  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
477  cells[c].vertices[v] = new_vertex_numbers[cells[c].vertices[v]];
478 
479  // same for boundary data
480  for (unsigned int c = 0; c < subcelldata.boundary_lines.size(); ++c)
481  for (unsigned int v = 0; v < GeometryInfo<1>::vertices_per_cell; ++v)
482  {
483  Assert(subcelldata.boundary_lines[c].vertices[v] <
484  new_vertex_numbers.size(),
485  ExcMessage(
486  "Invalid vertex index in subcelldata.boundary_lines. "
487  "subcelldata.boundary_lines[" +
488  Utilities::int_to_string(c) + "].vertices[" +
489  Utilities::int_to_string(v) + "]=" +
491  subcelldata.boundary_lines[c].vertices[v]) +
492  " is invalid, because only " +
493  Utilities::int_to_string(vertices.size()) +
494  " vertices were supplied."));
495  subcelldata.boundary_lines[c].vertices[v] =
496  new_vertex_numbers[subcelldata.boundary_lines[c].vertices[v]];
497  }
498 
499  for (unsigned int c = 0; c < subcelldata.boundary_quads.size(); ++c)
500  for (unsigned int v = 0; v < GeometryInfo<2>::vertices_per_cell; ++v)
501  {
502  Assert(subcelldata.boundary_quads[c].vertices[v] <
503  new_vertex_numbers.size(),
504  ExcMessage(
505  "Invalid vertex index in subcelldata.boundary_quads. "
506  "subcelldata.boundary_quads[" +
507  Utilities::int_to_string(c) + "].vertices[" +
508  Utilities::int_to_string(v) + "]=" +
510  subcelldata.boundary_quads[c].vertices[v]) +
511  " is invalid, because only " +
512  Utilities::int_to_string(vertices.size()) +
513  " vertices were supplied."));
514 
515  subcelldata.boundary_quads[c].vertices[v] =
516  new_vertex_numbers[subcelldata.boundary_quads[c].vertices[v]];
517  }
518 
519  // finally copy over the vertices which we really need to a new array and
520  // replace the old one by the new one
521  std::vector<Point<spacedim>> tmp;
522  tmp.reserve(std::count(vertex_used.begin(), vertex_used.end(), true));
523  for (unsigned int v = 0; v < vertices.size(); ++v)
524  if (vertex_used[v] == true)
525  tmp.push_back(vertices[v]);
526  swap(vertices, tmp);
527  }
528 
529 
530 
531  template <int dim, int spacedim>
532  void
534  std::vector<CellData<dim>> & cells,
535  SubCellData & subcelldata,
536  std::vector<unsigned int> & considered_vertices,
537  double tol)
538  {
539  // create a vector of vertex
540  // indices. initialize it to the identity,
541  // later on change that if necessary.
542  std::vector<unsigned int> new_vertex_numbers(vertices.size());
543  for (unsigned int i = 0; i < vertices.size(); ++i)
544  new_vertex_numbers[i] = i;
545 
546  // if the considered_vertices vector is
547  // empty, consider all vertices
548  if (considered_vertices.size() == 0)
549  considered_vertices = new_vertex_numbers;
550 
551  Assert(considered_vertices.size() <= vertices.size(), ExcInternalError());
552 
553 
554  // now loop over all vertices to be
555  // considered and try to find an identical
556  // one
557  for (unsigned int i = 0; i < considered_vertices.size(); ++i)
558  {
559  Assert(considered_vertices[i] < vertices.size(), ExcInternalError());
560  if (new_vertex_numbers[considered_vertices[i]] !=
561  considered_vertices[i])
562  // this vertex has been identified with
563  // another one already, skip it in the
564  // test
565  continue;
566  // this vertex is not identified with
567  // another one so far. search in the list
568  // of remaining vertices. if a duplicate
569  // vertex is found, set the new vertex
570  // index for that vertex to this vertex'
571  // index.
572  for (unsigned int j = i + 1; j < considered_vertices.size(); ++j)
573  {
574  bool equal = true;
575  for (unsigned int d = 0; d < spacedim; ++d)
576  equal &= (fabs(vertices[considered_vertices[j]](d) -
577  vertices[considered_vertices[i]](d)) < tol);
578  if (equal)
579  {
580  new_vertex_numbers[considered_vertices[j]] =
581  considered_vertices[i];
582  }
583  }
584  }
585 
586  // now we got a renumbering list. simply renumber all vertices
587  // (non-duplicate vertices get renumbered to themselves, so nothing bad
588  // happens). after that, the duplicate vertices will be unused, so call
589  // delete_unused_vertices() to do that part of the job.
590  for (auto &cell : cells)
591  for (auto &vertex_index : cell.vertices)
592  vertex_index = new_vertex_numbers[vertex_index];
593  for (auto &quad : subcelldata.boundary_quads)
594  for (auto &vertex_index : quad.vertices)
595  vertex_index = new_vertex_numbers[vertex_index];
596  for (auto &line : subcelldata.boundary_lines)
597  for (auto &vertex_index : line.vertices)
598  vertex_index = new_vertex_numbers[vertex_index];
599 
600  delete_unused_vertices(vertices, cells, subcelldata);
601  }
602 
603 
604 
605  // define some transformations in an anonymous namespace
606  namespace
607  {
608  template <int spacedim>
609  class Shift
610  {
611  public:
612  explicit Shift(const Tensor<1, spacedim> &shift)
613  : shift(shift)
614  {}
616  operator()(const Point<spacedim> p) const
617  {
618  return p + shift;
619  }
620 
621  private:
623  };
624 
625 
626  // the following class is only
627  // needed in 2d, so avoid trouble
628  // with compilers warning otherwise
629  class Rotate2d
630  {
631  public:
632  explicit Rotate2d(const double angle)
633  : angle(angle)
634  {}
635  Point<2>
636  operator()(const Point<2> &p) const
637  {
638  return Point<2>(std::cos(angle) * p(0) - std::sin(angle) * p(1),
639  std::sin(angle) * p(0) + std::cos(angle) * p(1));
640  }
641 
642  private:
643  const double angle;
644  };
645 
646  // Transformation to rotate around one of the cartesian axes.
647  class Rotate3d
648  {
649  public:
650  Rotate3d(const double angle, const unsigned int axis)
651  : angle(angle)
652  , axis(axis)
653  {}
654 
655  Point<3>
656  operator()(const Point<3> &p) const
657  {
658  if (axis == 0)
659  return Point<3>(p(0),
660  std::cos(angle) * p(1) - std::sin(angle) * p(2),
661  std::sin(angle) * p(1) + std::cos(angle) * p(2));
662  else if (axis == 1)
663  return Point<3>(std::cos(angle) * p(0) + std::sin(angle) * p(2),
664  p(1),
665  -std::sin(angle) * p(0) + std::cos(angle) * p(2));
666  else
667  return Point<3>(std::cos(angle) * p(0) - std::sin(angle) * p(1),
668  std::sin(angle) * p(0) + std::cos(angle) * p(1),
669  p(2));
670  }
671 
672  private:
673  const double angle;
674  const unsigned int axis;
675  };
676 
677  template <int spacedim>
678  class Scale
679  {
680  public:
681  explicit Scale(const double factor)
682  : factor(factor)
683  {}
685  operator()(const Point<spacedim> p) const
686  {
687  return p * factor;
688  }
689 
690  private:
691  const double factor;
692  };
693  } // namespace
694 
695 
696  template <int dim, int spacedim>
697  void
698  shift(const Tensor<1, spacedim> & shift_vector,
699  Triangulation<dim, spacedim> &triangulation)
700  {
701  transform(Shift<spacedim>(shift_vector), triangulation);
702  }
703 
704 
705 
706  void
707  rotate(const double angle, Triangulation<2> &triangulation)
708  {
709  transform(Rotate2d(angle), triangulation);
710  }
711 
712  template <int dim>
713  void
714  rotate(const double angle,
715  const unsigned int axis,
716  Triangulation<dim, 3> &triangulation)
717  {
718  Assert(axis < 3, ExcMessage("Invalid axis given!"));
719 
720  transform(Rotate3d(angle, axis), triangulation);
721  }
722 
723  template <int dim, int spacedim>
724  void
725  scale(const double scaling_factor,
726  Triangulation<dim, spacedim> &triangulation)
727  {
728  Assert(scaling_factor > 0, ExcScalingFactorNotPositive(scaling_factor));
729  transform(Scale<spacedim>(scaling_factor), triangulation);
730  }
731 
732 
733  namespace
734  {
740  void
741  laplace_solve(const SparseMatrix<double> & S,
742  const std::map<types::global_dof_index, double> &fixed_dofs,
743  Vector<double> & u)
744  {
745  const unsigned int n_dofs = S.n();
748  prec.initialize(S, 1.2);
750 
751  SolverControl control(n_dofs, 1.e-10, false, false);
753  SolverCG<Vector<double>> solver(control, mem);
754 
755  Vector<double> f(n_dofs);
756 
757  SF.add_constraints(fixed_dofs);
758  SF.apply_constraints(f, true);
759  solver.solve(SF, u, f, PF);
760  }
761  } // namespace
762 
763 
764 
765  // Implementation for 1D only
766  template <>
767  void
768  laplace_transform(const std::map<unsigned int, Point<1>> &,
770  const Function<1> *,
771  const bool)
772  {
773  Assert(false, ExcNotImplemented());
774  }
775 
776 
777  // Implementation for dimensions except 1
778  template <int dim>
779  void
780  laplace_transform(const std::map<unsigned int, Point<dim>> &new_points,
781  Triangulation<dim> & triangulation,
782  const Function<dim> * coefficient,
783  const bool solve_for_absolute_positions)
784  {
785  // first provide everything that is needed for solving a Laplace
786  // equation.
787  FE_Q<dim> q1(1);
788 
789  DoFHandler<dim> dof_handler(triangulation);
790  dof_handler.distribute_dofs(q1);
791 
792  DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
793  DoFTools::make_sparsity_pattern(dof_handler, dsp);
794  dsp.compress();
795 
796  SparsityPattern sparsity_pattern;
797  sparsity_pattern.copy_from(dsp);
798  sparsity_pattern.compress();
799 
800  SparseMatrix<double> S(sparsity_pattern);
801 
802  QGauss<dim> quadrature(4);
803 
805  StaticMappingQ1<dim>::mapping, dof_handler, quadrature, S, coefficient);
806 
807  // set up the boundary values for the laplace problem
808  std::map<types::global_dof_index, double> fixed_dofs[dim];
809  typename std::map<unsigned int, Point<dim>>::const_iterator map_end =
810  new_points.end();
811 
812  // fill these maps using the data given by new_points
813  typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin_active(),
814  endc = dof_handler.end();
815  for (; cell != endc; ++cell)
816  {
817  // loop over all vertices of the cell and see if it is listed in the map
818  // given as first argument of the function
819  for (unsigned int vertex_no = 0;
820  vertex_no < GeometryInfo<dim>::vertices_per_cell;
821  ++vertex_no)
822  {
823  const unsigned int vertex_index = cell->vertex_index(vertex_no);
824  const Point<dim> & vertex_point = cell->vertex(vertex_no);
825 
826  const typename std::map<unsigned int, Point<dim>>::const_iterator
827  map_iter = new_points.find(vertex_index);
828 
829  if (map_iter != map_end)
830  for (unsigned int i = 0; i < dim; ++i)
831  fixed_dofs[i].insert(std::pair<types::global_dof_index, double>(
832  cell->vertex_dof_index(vertex_no, 0),
833  (solve_for_absolute_positions ?
834  map_iter->second(i) :
835  map_iter->second(i) - vertex_point[i])));
836  }
837  }
838 
839  // solve the dim problems with different right hand sides.
840  Vector<double> us[dim];
841  for (unsigned int i = 0; i < dim; ++i)
842  us[i].reinit(dof_handler.n_dofs());
843 
844  // solve linear systems in parallel
845  Threads::TaskGroup<> tasks;
846  for (unsigned int i = 0; i < dim; ++i)
847  tasks += Threads::new_task(&laplace_solve, S, fixed_dofs[i], us[i]);
848  tasks.join_all();
849 
850  // change the coordinates of the points of the triangulation
851  // according to the computed values
852  std::vector<bool> vertex_touched(triangulation.n_vertices(), false);
853  for (cell = dof_handler.begin_active(); cell != endc; ++cell)
854  for (unsigned int vertex_no = 0;
855  vertex_no < GeometryInfo<dim>::vertices_per_cell;
856  ++vertex_no)
857  if (vertex_touched[cell->vertex_index(vertex_no)] == false)
858  {
859  Point<dim> &v = cell->vertex(vertex_no);
860 
861  const types::global_dof_index dof_index =
862  cell->vertex_dof_index(vertex_no, 0);
863  for (unsigned int i = 0; i < dim; ++i)
864  if (solve_for_absolute_positions)
865  v(i) = us[i](dof_index);
866  else
867  v(i) += us[i](dof_index);
868 
869  vertex_touched[cell->vertex_index(vertex_no)] = true;
870  }
871  }
872 
873  template <int dim, int spacedim>
874  std::map<unsigned int, Point<spacedim>>
876  {
877  std::map<unsigned int, Point<spacedim>> vertex_map;
879  cell = tria.begin_active(),
880  endc = tria.end();
881  for (; cell != endc; ++cell)
882  {
883  for (unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell; ++i)
884  {
885  const typename Triangulation<dim, spacedim>::face_iterator &face =
886  cell->face(i);
887  if (face->at_boundary())
888  {
889  for (unsigned j = 0; j < GeometryInfo<dim>::vertices_per_face;
890  ++j)
891  {
892  const Point<spacedim> &vertex = face->vertex(j);
893  const unsigned int vertex_index = face->vertex_index(j);
894  vertex_map[vertex_index] = vertex;
895  }
896  }
897  }
898  }
899  return vertex_map;
900  }
901 
906  template <int dim, int spacedim>
907  void
908  distort_random(const double factor,
909  Triangulation<dim, spacedim> &triangulation,
910  const bool keep_boundary)
911  {
912  // if spacedim>dim we need to make sure that we perturb
913  // points but keep them on
914  // the manifold. however, this isn't implemented right now
915  Assert(spacedim == dim, ExcNotImplemented());
916 
917 
918  // find the smallest length of the
919  // lines adjacent to the
920  // vertex. take the initial value
921  // to be larger than anything that
922  // might be found: the diameter of
923  // the triangulation, here
924  // estimated by adding up the
925  // diameters of the coarse grid
926  // cells.
927  double almost_infinite_length = 0;
929  triangulation.begin(0);
930  cell != triangulation.end(0);
931  ++cell)
932  almost_infinite_length += cell->diameter();
933 
934  std::vector<double> minimal_length(triangulation.n_vertices(),
935  almost_infinite_length);
936 
937  // also note if a vertex is at the boundary
938  std::vector<bool> at_boundary(keep_boundary ? triangulation.n_vertices() :
939  0,
940  false);
941  // for parallel::shared::Triangulation we need to work on all vertices,
942  // not just the ones related to loacally owned cells;
943  const bool is_parallel_shared =
945  &triangulation) != nullptr);
947  triangulation.begin_active();
948  cell != triangulation.end();
949  ++cell)
950  if (is_parallel_shared || cell->is_locally_owned())
951  {
952  if (dim > 1)
953  {
954  for (unsigned int i = 0; i < GeometryInfo<dim>::lines_per_cell;
955  ++i)
956  {
957  const typename Triangulation<dim, spacedim>::line_iterator
958  line = cell->line(i);
959 
960  if (keep_boundary && line->at_boundary())
961  {
962  at_boundary[line->vertex_index(0)] = true;
963  at_boundary[line->vertex_index(1)] = true;
964  }
965 
966  minimal_length[line->vertex_index(0)] =
967  std::min(line->diameter(),
968  minimal_length[line->vertex_index(0)]);
969  minimal_length[line->vertex_index(1)] =
970  std::min(line->diameter(),
971  minimal_length[line->vertex_index(1)]);
972  }
973  }
974  else // dim==1
975  {
976  if (keep_boundary)
977  for (unsigned int vertex = 0; vertex < 2; ++vertex)
978  if (cell->at_boundary(vertex) == true)
979  at_boundary[cell->vertex_index(vertex)] = true;
980 
981  minimal_length[cell->vertex_index(0)] =
982  std::min(cell->diameter(),
983  minimal_length[cell->vertex_index(0)]);
984  minimal_length[cell->vertex_index(1)] =
985  std::min(cell->diameter(),
986  minimal_length[cell->vertex_index(1)]);
987  }
988  }
989 
990  // create a random number generator for the interval [-1,1]. we use
991  // this to make sure the distribution we get is repeatable, i.e.,
992  // if you call the function twice on the same mesh, then you will
993  // get the same mesh. this would not be the case if you used
994  // the rand() function, which carries around some internal state
995  boost::random::mt19937 rng;
996  boost::random::uniform_real_distribution<> uniform_distribution(-1, 1);
997 
998  // If the triangulation is distributed, we need to
999  // exchange the moved vertices across mpi processes
1001  *distributed_triangulation =
1003  &triangulation))
1004  {
1005  const std::vector<bool> locally_owned_vertices =
1006  get_locally_owned_vertices(triangulation);
1007  std::vector<bool> vertex_moved(triangulation.n_vertices(), false);
1008 
1009  // Next move vertices on locally owned cells
1011  triangulation.begin_active();
1012  cell != triangulation.end();
1013  ++cell)
1014  if (cell->is_locally_owned())
1015  {
1016  for (unsigned int vertex_no = 0;
1017  vertex_no < GeometryInfo<dim>::vertices_per_cell;
1018  ++vertex_no)
1019  {
1020  const unsigned global_vertex_no =
1021  cell->vertex_index(vertex_no);
1022 
1023  // ignore this vertex if we shall keep the boundary and
1024  // this vertex *is* at the boundary, if it is already moved
1025  // or if another process moves this vertex
1026  if ((keep_boundary && at_boundary[global_vertex_no]) ||
1027  vertex_moved[global_vertex_no] ||
1028  !locally_owned_vertices[global_vertex_no])
1029  continue;
1030 
1031  // first compute a random shift vector
1032  Point<spacedim> shift_vector;
1033  for (unsigned int d = 0; d < spacedim; ++d)
1034  shift_vector(d) = uniform_distribution(rng);
1035 
1036  shift_vector *= factor * minimal_length[global_vertex_no] /
1037  std::sqrt(shift_vector.square());
1038 
1039  // finally move the vertex
1040  cell->vertex(vertex_no) += shift_vector;
1041  vertex_moved[global_vertex_no] = true;
1042  }
1043  }
1044 
1045 #ifdef DEAL_II_WITH_P4EST
1046  distributed_triangulation->communicate_locally_moved_vertices(
1047  locally_owned_vertices);
1048 #else
1049  (void)distributed_triangulation;
1050  Assert(false, ExcInternalError());
1051 #endif
1052  }
1053  else
1054  // if this is a sequential triangulation, we could in principle
1055  // use the algorithm above, but we'll use an algorithm that we used
1056  // before the parallel::distributed::Triangulation was introduced
1057  // in order to preserve backward compatibility
1058  {
1059  // loop over all vertices and compute their new locations
1060  const unsigned int n_vertices = triangulation.n_vertices();
1061  std::vector<Point<spacedim>> new_vertex_locations(n_vertices);
1062  const std::vector<Point<spacedim>> &old_vertex_locations =
1063  triangulation.get_vertices();
1064 
1065  for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
1066  {
1067  // ignore this vertex if we will keep the boundary and
1068  // this vertex *is* at the boundary
1069  if (keep_boundary && at_boundary[vertex])
1070  new_vertex_locations[vertex] = old_vertex_locations[vertex];
1071  else
1072  {
1073  // compute a random shift vector
1074  Point<spacedim> shift_vector;
1075  for (unsigned int d = 0; d < spacedim; ++d)
1076  shift_vector(d) = uniform_distribution(rng);
1077 
1078  shift_vector *= factor * minimal_length[vertex] /
1079  std::sqrt(shift_vector.square());
1080 
1081  // record new vertex location
1082  new_vertex_locations[vertex] =
1083  old_vertex_locations[vertex] + shift_vector;
1084  }
1085  }
1086 
1087  // now do the actual move of the vertices
1089  triangulation.begin_active();
1090  cell != triangulation.end();
1091  ++cell)
1092  for (unsigned int vertex_no = 0;
1093  vertex_no < GeometryInfo<dim>::vertices_per_cell;
1094  ++vertex_no)
1095  cell->vertex(vertex_no) =
1096  new_vertex_locations[cell->vertex_index(vertex_no)];
1097  }
1098 
1099  // Correct hanging nodes if necessary
1100  if (dim >= 2)
1101  {
1102  // We do the same as in GridTools::transform
1103  //
1104  // exclude hanging nodes at the boundaries of artificial cells:
1105  // these may belong to ghost cells for which we know the exact
1106  // location of vertices, whereas the artificial cell may or may
1107  // not be further refined, and so we cannot know whether
1108  // the location of the hanging node is correct or not
1110  cell = triangulation.begin_active(),
1111  endc = triangulation.end();
1112  for (; cell != endc; ++cell)
1113  if (!cell->is_artificial())
1114  for (unsigned int face = 0;
1115  face < GeometryInfo<dim>::faces_per_cell;
1116  ++face)
1117  if (cell->face(face)->has_children() &&
1118  !cell->face(face)->at_boundary())
1119  {
1120  // this face has hanging nodes
1121  if (dim == 2)
1122  cell->face(face)->child(0)->vertex(1) =
1123  (cell->face(face)->vertex(0) +
1124  cell->face(face)->vertex(1)) /
1125  2;
1126  else if (dim == 3)
1127  {
1128  cell->face(face)->child(0)->vertex(1) =
1129  .5 * (cell->face(face)->vertex(0) +
1130  cell->face(face)->vertex(1));
1131  cell->face(face)->child(0)->vertex(2) =
1132  .5 * (cell->face(face)->vertex(0) +
1133  cell->face(face)->vertex(2));
1134  cell->face(face)->child(1)->vertex(3) =
1135  .5 * (cell->face(face)->vertex(1) +
1136  cell->face(face)->vertex(3));
1137  cell->face(face)->child(2)->vertex(3) =
1138  .5 * (cell->face(face)->vertex(2) +
1139  cell->face(face)->vertex(3));
1140 
1141  // center of the face
1142  cell->face(face)->child(0)->vertex(3) =
1143  .25 * (cell->face(face)->vertex(0) +
1144  cell->face(face)->vertex(1) +
1145  cell->face(face)->vertex(2) +
1146  cell->face(face)->vertex(3));
1147  }
1148  }
1149  }
1150  }
1151 
1152 
1153 
1154  template <int dim, template <int, int> class MeshType, int spacedim>
1155  unsigned int
1156  find_closest_vertex(const MeshType<dim, spacedim> &mesh,
1157  const Point<spacedim> & p,
1158  const std::vector<bool> & marked_vertices)
1159  {
1160  // first get the underlying
1161  // triangulation from the
1162  // mesh and determine vertices
1163  // and used vertices
1164  const Triangulation<dim, spacedim> &tria = mesh.get_triangulation();
1165 
1166  const std::vector<Point<spacedim>> &vertices = tria.get_vertices();
1167 
1168  Assert(tria.get_vertices().size() == marked_vertices.size() ||
1169  marked_vertices.size() == 0,
1170  ExcDimensionMismatch(tria.get_vertices().size(),
1171  marked_vertices.size()));
1172 
1173  // If p is an element of marked_vertices,
1174  // and q is that of used_Vertices,
1175  // the vector marked_vertices does NOT
1176  // contain unused vertices if p implies q.
1177  // I.e., if p is true q must be true
1178  // (if p is false, q could be false or true).
1179  // p implies q logic is encapsulated in ~p|q.
1180  Assert(
1181  marked_vertices.size() == 0 ||
1182  std::equal(marked_vertices.begin(),
1183  marked_vertices.end(),
1184  tria.get_used_vertices().begin(),
1185  [](bool p, bool q) { return !p || q; }),
1186  ExcMessage(
1187  "marked_vertices should be a subset of used vertices in the triangulation "
1188  "but marked_vertices contains one or more vertices that are not used vertices!"));
1189 
1190  // In addition, if a vector bools
1191  // is specified (marked_vertices)
1192  // marking all the vertices which
1193  // could be the potentially closest
1194  // vertex to the point, use it instead
1195  // of used vertices
1196  const std::vector<bool> &used = (marked_vertices.size() == 0) ?
1197  tria.get_used_vertices() :
1198  marked_vertices;
1199 
1200  // At the beginning, the first
1201  // used vertex is the closest one
1202  std::vector<bool>::const_iterator first =
1203  std::find(used.begin(), used.end(), true);
1204 
1205  // Assert that at least one vertex
1206  // is actually used
1207  Assert(first != used.end(), ExcInternalError());
1208 
1209  unsigned int best_vertex = std::distance(used.begin(), first);
1210  double best_dist = (p - vertices[best_vertex]).norm_square();
1211 
1212  // For all remaining vertices, test
1213  // whether they are any closer
1214  for (unsigned int j = best_vertex + 1; j < vertices.size(); j++)
1215  if (used[j])
1216  {
1217  double dist = (p - vertices[j]).norm_square();
1218  if (dist < best_dist)
1219  {
1220  best_vertex = j;
1221  best_dist = dist;
1222  }
1223  }
1224 
1225  return best_vertex;
1226  }
1227 
1228 
1229 
1230  template <int dim, template <int, int> class MeshType, int spacedim>
1231  unsigned int
1233  const MeshType<dim, spacedim> &mesh,
1234  const Point<spacedim> & p,
1235  const std::vector<bool> & marked_vertices)
1236  {
1237  // Take a shortcut in the simple case.
1238  if (mapping.preserves_vertex_locations() == true)
1239  return find_closest_vertex(mesh, p, marked_vertices);
1240 
1241  // first get the underlying
1242  // triangulation from the
1243  // mesh and determine vertices
1244  // and used vertices
1245  const Triangulation<dim, spacedim> &tria = mesh.get_triangulation();
1246 
1247  auto vertices = extract_used_vertices(tria, mapping);
1248 
1249  Assert(tria.get_vertices().size() == marked_vertices.size() ||
1250  marked_vertices.size() == 0,
1251  ExcDimensionMismatch(tria.get_vertices().size(),
1252  marked_vertices.size()));
1253 
1254  // If p is an element of marked_vertices,
1255  // and q is that of used_Vertices,
1256  // the vector marked_vertices does NOT
1257  // contain unused vertices if p implies q.
1258  // I.e., if p is true q must be true
1259  // (if p is false, q could be false or true).
1260  // p implies q logic is encapsulated in ~p|q.
1261  Assert(
1262  marked_vertices.size() == 0 ||
1263  std::equal(marked_vertices.begin(),
1264  marked_vertices.end(),
1265  tria.get_used_vertices().begin(),
1266  [](bool p, bool q) { return !p || q; }),
1267  ExcMessage(
1268  "marked_vertices should be a subset of used vertices in the triangulation "
1269  "but marked_vertices contains one or more vertices that are not used vertices!"));
1270 
1271  // Remove from the map unwanted elements.
1272  if (marked_vertices.size())
1273  for (auto it = vertices.begin(); it != vertices.end();)
1274  {
1275  if (marked_vertices[it->first] == false)
1276  {
1277  vertices.erase(it++);
1278  }
1279  else
1280  {
1281  ++it;
1282  }
1283  }
1284 
1285  return find_closest_vertex(vertices, p);
1286  }
1287 
1288 
1289 
1290  template <int dim, template <int, int> class MeshType, int spacedim>
1291 #ifndef _MSC_VER
1292  std::vector<typename MeshType<dim, spacedim>::active_cell_iterator>
1293 #else
1294  std::vector<
1295  typename ::internal::
1296  ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type>
1297 #endif
1298  find_cells_adjacent_to_vertex(const MeshType<dim, spacedim> &mesh,
1299  const unsigned int vertex)
1300  {
1301  // make sure that the given vertex is
1302  // an active vertex of the underlying
1303  // triangulation
1304  Assert(vertex < mesh.get_triangulation().n_vertices(),
1305  ExcIndexRange(0, mesh.get_triangulation().n_vertices(), vertex));
1306  Assert(mesh.get_triangulation().get_used_vertices()[vertex],
1307  ExcVertexNotUsed(vertex));
1308 
1309  // use a set instead of a vector
1310  // to ensure that cells are inserted only
1311  // once
1312  std::set<typename ::internal::
1313  ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type>
1314  adjacent_cells;
1315 
1316  typename ::internal::
1317  ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type
1318  cell = mesh.begin_active(),
1319  endc = mesh.end();
1320 
1321  // go through all active cells and look if the vertex is part of that cell
1322  //
1323  // in 1d, this is all we need to care about. in 2d/3d we also need to worry
1324  // that the vertex might be a hanging node on a face or edge of a cell; in
1325  // this case, we would want to add those cells as well on whose faces the
1326  // vertex is located but for which it is not a vertex itself.
1327  //
1328  // getting this right is a lot simpler in 2d than in 3d. in 2d, a hanging
1329  // node can only be in the middle of a face and we can query the neighboring
1330  // cell from the current cell. on the other hand, in 3d a hanging node
1331  // vertex can also be on an edge but there can be many other cells on
1332  // this edge and we can not access them from the cell we are currently
1333  // on.
1334  //
1335  // so, in the 3d case, if we run the algorithm as in 2d, we catch all
1336  // those cells for which the vertex we seek is on a *subface*, but we
1337  // miss the case of cells for which the vertex we seek is on a
1338  // sub-edge for which there is no corresponding sub-face (because the
1339  // immediate neighbor behind this face is not refined), see for example
1340  // the bits/find_cells_adjacent_to_vertex_6 testcase. thus, if we
1341  // haven't yet found the vertex for the current cell we also need to
1342  // look at the mid-points of edges
1343  //
1344  // as a final note, deciding whether a neighbor is actually coarser is
1345  // simple in the case of isotropic refinement (we just need to look at
1346  // the level of the current and the neighboring cell). however, this
1347  // isn't so simple if we have used anisotropic refinement since then
1348  // the level of a cell is not indicative of whether it is coarser or
1349  // not than the current cell. ultimately, we want to add all cells on
1350  // which the vertex is, independent of whether they are coarser or
1351  // finer and so in the 2d case below we simply add *any* *active* neighbor.
1352  // in the worst case, we add cells multiple times to the adjacent_cells
1353  // list, but std::set throws out those cells already entered
1354  for (; cell != endc; ++cell)
1355  {
1356  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; v++)
1357  if (cell->vertex_index(v) == vertex)
1358  {
1359  // OK, we found a cell that contains
1360  // the given vertex. We add it
1361  // to the list.
1362  adjacent_cells.insert(cell);
1363 
1364  // as explained above, in 2+d we need to check whether
1365  // this vertex is on a face behind which there is a
1366  // (possibly) coarser neighbor. if this is the case,
1367  // then we need to also add this neighbor
1368  if (dim >= 2)
1369  for (unsigned int vface = 0; vface < dim; vface++)
1370  {
1371  const unsigned int face =
1373 
1374  if (!cell->at_boundary(face) &&
1375  cell->neighbor(face)->active())
1376  {
1377  // there is a (possibly) coarser cell behind a
1378  // face to which the vertex belongs. the
1379  // vertex we are looking at is then either a
1380  // vertex of that coarser neighbor, or it is a
1381  // hanging node on one of the faces of that
1382  // cell. in either case, it is adjacent to the
1383  // vertex, so add it to the list as well (if
1384  // the cell was already in the list then the
1385  // std::set makes sure that we get it only
1386  // once)
1387  adjacent_cells.insert(cell->neighbor(face));
1388  }
1389  }
1390 
1391  // in any case, we have found a cell, so go to the next cell
1392  goto next_cell;
1393  }
1394 
1395  // in 3d also loop over the edges
1396  if (dim >= 3)
1397  {
1398  for (unsigned int e = 0; e < GeometryInfo<dim>::lines_per_cell; ++e)
1399  if (cell->line(e)->has_children())
1400  // the only place where this vertex could have been
1401  // hiding is on the mid-edge point of the edge we
1402  // are looking at
1403  if (cell->line(e)->child(0)->vertex_index(1) == vertex)
1404  {
1405  adjacent_cells.insert(cell);
1406 
1407  // jump out of this tangle of nested loops
1408  goto next_cell;
1409  }
1410  }
1411 
1412  // in more than 3d we would probably have to do the same as
1413  // above also for even lower-dimensional objects
1414  Assert(dim <= 3, ExcNotImplemented());
1415 
1416  // move on to the next cell if we have found the
1417  // vertex on the current one
1418  next_cell:;
1419  }
1420 
1421  // if this was an active vertex then there needs to have been
1422  // at least one cell to which it is adjacent!
1423  Assert(adjacent_cells.size() > 0, ExcInternalError());
1424 
1425  // return the result as a vector, rather than the set we built above
1426  return std::vector<
1427  typename ::internal::
1428  ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type>(
1429  adjacent_cells.begin(), adjacent_cells.end());
1430  }
1431 
1432 
1433 
1434  template <int dim, int spacedim>
1435  std::vector<std::vector<Tensor<1, spacedim>>>
1437  const Triangulation<dim, spacedim> &mesh,
1438  const std::vector<
1440  &vertex_to_cells)
1441  {
1442  const std::vector<Point<spacedim>> &vertices = mesh.get_vertices();
1443  const unsigned int n_vertices = vertex_to_cells.size();
1444 
1445  AssertDimension(vertices.size(), n_vertices);
1446 
1447 
1448  std::vector<std::vector<Tensor<1, spacedim>>> vertex_to_cell_centers(
1449  n_vertices);
1450  for (unsigned int vertex = 0; vertex < n_vertices; ++vertex)
1451  if (mesh.vertex_used(vertex))
1452  {
1453  const unsigned int n_neighbor_cells = vertex_to_cells[vertex].size();
1454  vertex_to_cell_centers[vertex].resize(n_neighbor_cells);
1455 
1456  typename std::set<typename Triangulation<dim, spacedim>::
1457  active_cell_iterator>::iterator it =
1458  vertex_to_cells[vertex].begin();
1459  for (unsigned int cell = 0; cell < n_neighbor_cells; ++cell, ++it)
1460  {
1461  vertex_to_cell_centers[vertex][cell] =
1462  (*it)->center() - vertices[vertex];
1463  vertex_to_cell_centers[vertex][cell] /=
1464  vertex_to_cell_centers[vertex][cell].norm();
1465  }
1466  }
1467  return vertex_to_cell_centers;
1468  }
1469 
1470 
1471  namespace
1472  {
1473  template <int spacedim>
1474  bool
1475  compare_point_association(
1476  const unsigned int a,
1477  const unsigned int b,
1478  const Tensor<1, spacedim> & point_direction,
1479  const std::vector<Tensor<1, spacedim>> &center_directions)
1480  {
1481  const double scalar_product_a = center_directions[a] * point_direction;
1482  const double scalar_product_b = center_directions[b] * point_direction;
1483 
1484  // The function is supposed to return if a is before b. We are looking
1485  // for the alignment of point direction and center direction, therefore
1486  // return if the scalar product of a is larger.
1487  return (scalar_product_a > scalar_product_b);
1488  }
1489  } // namespace
1490 
1491  template <int dim, template <int, int> class MeshType, int spacedim>
1492 #ifndef _MSC_VER
1493  std::pair<typename MeshType<dim, spacedim>::active_cell_iterator, Point<dim>>
1494 #else
1495  std::pair<typename ::internal::
1496  ActiveCellIterator<dim, spacedim, MeshType<dim, spacedim>>::type,
1497  Point<dim>>
1498 #endif
1500  const Mapping<dim, spacedim> & mapping,
1501  const MeshType<dim, spacedim> &mesh,
1502  const Point<spacedim> & p,
1503  const std::vector<
1504  std::set<typename MeshType<dim, spacedim>::active_cell_iterator>>
1505  & vertex_to_cells,
1506  const std::vector<std::vector<Tensor<1, spacedim>>> &vertex_to_cell_centers,
1507  const typename MeshType<dim, spacedim>::active_cell_iterator &cell_hint,
1508  const std::vector<bool> &marked_vertices)
1509  {
1510  std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
1511  Point<dim>>
1512  cell_and_position;
1513  // To handle points at the border we keep track of points which are close to
1514  // the unit cell:
1515  std::pair<typename MeshType<dim, spacedim>::active_cell_iterator,
1516  Point<dim>>
1517  cell_and_position_approx;
1518 
1519  bool found_cell = false;
1520  bool approx_cell = false;
1521 
1522  unsigned int closest_vertex_index = 0;
1523  Tensor<1, spacedim> vertex_to_point;
1524  auto current_cell = cell_hint;
1525 
1526  while (found_cell == false)
1527  {
1528  // First look at the vertices of the cell cell_hint. If it's an
1529  // invalid cell, then query for the closest global vertex
1530  if (current_cell.state() == IteratorState::valid)
1531  {
1532  const unsigned int closest_vertex =
1533  find_closest_vertex_of_cell<dim, spacedim>(current_cell, p);
1534  vertex_to_point = p - current_cell->vertex(closest_vertex);
1535  closest_vertex_index = current_cell->vertex_index(closest_vertex);
1536  }
1537  else
1538  {
1539  closest_vertex_index =
1540  GridTools::find_closest_vertex(mesh, p, marked_vertices);
1541  vertex_to_point = p - mesh.get_vertices()[closest_vertex_index];
1542  }
1543 
1544  const double vertex_point_norm = vertex_to_point.norm();
1545  if (vertex_point_norm > 0)
1546  vertex_to_point /= vertex_point_norm;
1547 
1548  const unsigned int n_neighbor_cells =
1549  vertex_to_cells[closest_vertex_index].size();
1550 
1551  // Create a corresponding map of vectors from vertex to cell center
1552  std::vector<unsigned int> neighbor_permutation(n_neighbor_cells);
1553 
1554  for (unsigned int i = 0; i < n_neighbor_cells; ++i)
1555  neighbor_permutation[i] = i;
1556 
1557  auto comp = [&](const unsigned int a, const unsigned int b) -> bool {
1558  return compare_point_association<spacedim>(
1559  a,
1560  b,
1561  vertex_to_point,
1562  vertex_to_cell_centers[closest_vertex_index]);
1563  };
1564 
1565  std::sort(neighbor_permutation.begin(),
1566  neighbor_permutation.end(),
1567  comp);
1568  // It is possible the vertex is close
1569  // to an edge, thus we add a tolerance
1570  // setting it initially to 1e-10
1571  // to keep also the "best" cell
1572  double best_distance = 1e-10;
1573 
1574  // Search all of the cells adjacent to the closest vertex of the cell
1575  // hint Most likely we will find the point in them.
1576  for (unsigned int i = 0; i < n_neighbor_cells; ++i)
1577  {
1578  try
1579  {
1580  auto cell = vertex_to_cells[closest_vertex_index].begin();
1581  std::advance(cell, neighbor_permutation[i]);
1582  const Point<dim> p_unit =
1583  mapping.transform_real_to_unit_cell(*cell, p);
1585  {
1586  cell_and_position.first = *cell;
1587  cell_and_position.second = p_unit;
1588  found_cell = true;
1589  approx_cell = false;
1590  break;
1591  }
1592  // The point is not inside this cell: checking how far outside
1593  // it is and whether we want to use this cell as a backup if we
1594  // can't find a cell within which the point lies.
1595  const double dist =
1597  if (dist < best_distance)
1598  {
1599  best_distance = dist;
1600  cell_and_position_approx.first = *cell;
1601  cell_and_position_approx.second = p_unit;
1602  approx_cell = true;
1603  }
1604  }
1605  catch (typename Mapping<dim>::ExcTransformationFailed &)
1606  {}
1607  }
1608 
1609  if (found_cell == true)
1610  return cell_and_position;
1611  else if (approx_cell == true)
1612  return cell_and_position_approx;
1613 
1614  // The first time around, we check for vertices in the hint_cell. If
1615  // that does not work, we set the cell iterator to an invalid one, and
1616  // look for a global vertex close to the point. If that does not work,
1617  // we are in trouble, and just throw an exception.
1618  //
1619  // If we got here, then we did not find the point. If the
1620  // current_cell.state() here is not IteratorState::valid, it means that
1621  // the user did not provide a hint_cell, and at the beginning of the
1622  // while loop we performed an actual global search on the mesh
1623  // vertices. Not finding the point then means the point is outside the
1624  // domain.
1625  AssertThrow(current_cell.state() == IteratorState::valid,
1626  ExcPointNotFound<spacedim>(p));
1627 
1628  current_cell = typename MeshType<dim, spacedim>::active_cell_iterator();
1629  }
1630  return cell_and_position;
1631  }
1632 
1633 
1634 
1635  template <int dim, int spacedim>
1636  unsigned int
1639  const Point<spacedim> & position)
1640  {
1641  double minimum_distance = position.distance_square(cell->vertex(0));
1642  unsigned int closest_vertex = 0;
1643 
1644  for (unsigned int v = 1; v < GeometryInfo<dim>::vertices_per_cell; ++v)
1645  {
1646  const double vertex_distance =
1647  position.distance_square(cell->vertex(v));
1648  if (vertex_distance < minimum_distance)
1649  {
1650  closest_vertex = v;
1651  minimum_distance = vertex_distance;
1652  }
1653  }
1654  return closest_vertex;
1655  }
1656 
1657 
1658 
1659  namespace internal
1660  {
1661  namespace BoundingBoxPredicate
1662  {
1663  template <class MeshType>
1664  std::tuple<BoundingBox<MeshType::space_dimension>, bool>
1665  compute_cell_predicate_bounding_box(
1666  const typename MeshType::cell_iterator &parent_cell,
1667  const std::function<
1668  bool(const typename MeshType::active_cell_iterator &)> &predicate)
1669  {
1670  bool has_predicate =
1671  false; // Start assuming there's no cells with predicate inside
1672  std::vector<typename MeshType::active_cell_iterator> active_cells;
1673  if (parent_cell->active())
1674  active_cells = {parent_cell};
1675  else
1676  // Finding all active cells descendants of the current one (or the
1677  // current one if it is active)
1678  active_cells = get_active_child_cells<MeshType>(parent_cell);
1679 
1680  const unsigned int spacedim = MeshType::space_dimension;
1681 
1682  // Looking for the first active cell which has the property predicate
1683  unsigned int i = 0;
1684  while (i < active_cells.size() && !predicate(active_cells[i]))
1685  ++i;
1686 
1687  // No active cells or no active cells with property
1688  if (active_cells.size() == 0 || i == active_cells.size())
1689  {
1690  BoundingBox<spacedim> bbox;
1691  return std::make_tuple(bbox, has_predicate);
1692  }
1693 
1694  // The two boundary points defining the boundary box
1695  Point<spacedim> maxp = active_cells[i]->vertex(0);
1696  Point<spacedim> minp = active_cells[i]->vertex(0);
1697 
1698  for (; i < active_cells.size(); ++i)
1699  if (predicate(active_cells[i]))
1700  for (unsigned int v = 0;
1701  v < GeometryInfo<spacedim>::vertices_per_cell;
1702  ++v)
1703  for (unsigned int d = 0; d < spacedim; ++d)
1704  {
1705  minp[d] = std::min(minp[d], active_cells[i]->vertex(v)[d]);
1706  maxp[d] = std::max(maxp[d], active_cells[i]->vertex(v)[d]);
1707  }
1708 
1709  has_predicate = true;
1710  BoundingBox<spacedim> bbox(std::make_pair(minp, maxp));
1711  return std::make_tuple(bbox, has_predicate);
1712  }
1713  } // namespace BoundingBoxPredicate
1714  } // namespace internal
1715 
1716 
1717 
1718  template <class MeshType>
1719  std::vector<BoundingBox<MeshType::space_dimension>>
1721  const MeshType &mesh,
1722  const std::function<bool(const typename MeshType::active_cell_iterator &)>
1723  & predicate,
1724  const unsigned int refinement_level,
1725  const bool allow_merge,
1726  const unsigned int max_boxes)
1727  {
1728  // Algorithm brief description: begin with creating bounding boxes of all
1729  // cells at refinement_level (and coarser levels if there are active cells)
1730  // which have the predicate property. These are then merged
1731 
1732  Assert(
1733  refinement_level <= mesh.n_levels(),
1734  ExcMessage(
1735  "Error: refinement level is higher then total levels in the triangulation!"));
1736 
1737  const unsigned int spacedim = MeshType::space_dimension;
1738  std::vector<BoundingBox<spacedim>> bounding_boxes;
1739 
1740  // Creating a bounding box for all active cell on coarser level
1741 
1742  for (unsigned int i = 0; i < refinement_level; ++i)
1743  for (const typename MeshType::cell_iterator &cell :
1744  mesh.active_cell_iterators_on_level(i))
1745  {
1746  bool has_predicate = false;
1747  BoundingBox<spacedim> bbox;
1748  std::tie(bbox, has_predicate) =
1749  internal::BoundingBoxPredicate::compute_cell_predicate_bounding_box<
1750  MeshType>(cell, predicate);
1751  if (has_predicate)
1752  bounding_boxes.push_back(bbox);
1753  }
1754 
1755  // Creating a Bounding Box for all cells on the chosen refinement_level
1756  for (const typename MeshType::cell_iterator &cell :
1757  mesh.cell_iterators_on_level(refinement_level))
1758  {
1759  bool has_predicate = false;
1760  BoundingBox<spacedim> bbox;
1761  std::tie(bbox, has_predicate) =
1762  internal::BoundingBoxPredicate::compute_cell_predicate_bounding_box<
1763  MeshType>(cell, predicate);
1764  if (has_predicate)
1765  bounding_boxes.push_back(bbox);
1766  }
1767 
1768  if (!allow_merge)
1769  // If merging is not requested return the created bounding_boxes
1770  return bounding_boxes;
1771  else
1772  {
1773  // Merging part of the algorithm
1774  // Part 1: merging neighbors
1775  // This array stores the indices of arrays we have already merged
1776  std::vector<unsigned int> merged_boxes_idx;
1777  bool found_neighbors = true;
1778 
1779  // We merge only neighbors which can be expressed by a single bounding
1780  // box e.g. in 1d [0,1] and [1,2] can be described with [0,2] without
1781  // losing anything
1782  while (found_neighbors)
1783  {
1784  found_neighbors = false;
1785  for (unsigned int i = 0; i < bounding_boxes.size() - 1; ++i)
1786  {
1787  if (std::find(merged_boxes_idx.begin(),
1788  merged_boxes_idx.end(),
1789  i) == merged_boxes_idx.end())
1790  for (unsigned int j = i + 1; j < bounding_boxes.size(); ++j)
1791  if (std::find(merged_boxes_idx.begin(),
1792  merged_boxes_idx.end(),
1793  j) == merged_boxes_idx.end() &&
1794  bounding_boxes[i].get_neighbor_type(
1795  bounding_boxes[j]) ==
1796  NeighborType::mergeable_neighbors)
1797  {
1798  bounding_boxes[i].merge_with(bounding_boxes[j]);
1799  merged_boxes_idx.push_back(j);
1800  found_neighbors = true;
1801  }
1802  }
1803  }
1804 
1805  // Copying the merged boxes into merged_b_boxes
1806  std::vector<BoundingBox<spacedim>> merged_b_boxes;
1807  for (unsigned int i = 0; i < bounding_boxes.size(); ++i)
1808  if (std::find(merged_boxes_idx.begin(), merged_boxes_idx.end(), i) ==
1809  merged_boxes_idx.end())
1810  merged_b_boxes.push_back(bounding_boxes[i]);
1811 
1812  // Part 2: if there are too many bounding boxes, merging smaller boxes
1813  // This has sense only in dimension 2 or greater, since in dimension 1,
1814  // neighboring intervals can always be merged without problems
1815  if ((merged_b_boxes.size() > max_boxes) && (spacedim > 1))
1816  {
1817  std::vector<double> volumes;
1818  for (unsigned int i = 0; i < merged_b_boxes.size(); ++i)
1819  volumes.push_back(merged_b_boxes[i].volume());
1820 
1821  while (merged_b_boxes.size() > max_boxes)
1822  {
1823  unsigned int min_idx =
1824  std::min_element(volumes.begin(), volumes.end()) -
1825  volumes.begin();
1826  volumes.erase(volumes.begin() + min_idx);
1827  // Finding a neighbor
1828  bool not_removed = true;
1829  for (unsigned int i = 0;
1830  i < merged_b_boxes.size() && not_removed;
1831  ++i)
1832  // We merge boxes if we have "attached" or "mergeable"
1833  // neighbors, even though mergeable should be dealt with in
1834  // Part 1
1835  if (i != min_idx && (merged_b_boxes[i].get_neighbor_type(
1836  merged_b_boxes[min_idx]) ==
1837  NeighborType::attached_neighbors ||
1838  merged_b_boxes[i].get_neighbor_type(
1839  merged_b_boxes[min_idx]) ==
1840  NeighborType::mergeable_neighbors))
1841  {
1842  merged_b_boxes[i].merge_with(merged_b_boxes[min_idx]);
1843  merged_b_boxes.erase(merged_b_boxes.begin() + min_idx);
1844  not_removed = false;
1845  }
1846  Assert(!not_removed,
1847  ExcMessage("Error: couldn't merge bounding boxes!"));
1848  }
1849  }
1850  Assert(merged_b_boxes.size() <= max_boxes,
1851  ExcMessage(
1852  "Error: couldn't reach target number of bounding boxes!"));
1853  return merged_b_boxes;
1854  }
1855  }
1856 
1857 
1858 
1859  template <int spacedim>
1860 #ifndef DOXYGEN
1861  std::tuple<std::vector<std::vector<unsigned int>>,
1862  std::map<unsigned int, unsigned int>,
1863  std::map<unsigned int, std::vector<unsigned int>>>
1864 #else
1865  return_type
1866 #endif
1868  const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes,
1869  const std::vector<Point<spacedim>> & points)
1870  {
1871  unsigned int n_procs = global_bboxes.size();
1872  std::vector<std::vector<unsigned int>> point_owners(n_procs);
1873  std::map<unsigned int, unsigned int> map_owners_found;
1874  std::map<unsigned int, std::vector<unsigned int>> map_owners_guessed;
1875 
1876  unsigned int n_points = points.size();
1877  for (unsigned int pt = 0; pt < n_points; ++pt)
1878  {
1879  // Keep track of how many processes we guess to own the point
1880  std::vector<unsigned int> owners_found;
1881  // Check in which other processes the point might be
1882  for (unsigned int rk = 0; rk < n_procs; ++rk)
1883  {
1884  for (const BoundingBox<spacedim> &bbox : global_bboxes[rk])
1885  if (bbox.point_inside(points[pt]))
1886  {
1887  point_owners[rk].emplace_back(pt);
1888  owners_found.emplace_back(rk);
1889  break; // We can check now the next process
1890  }
1891  }
1892  Assert(owners_found.size() > 0,
1893  ExcMessage("No owners found for the point " +
1894  std::to_string(pt)));
1895  if (owners_found.size() == 1)
1896  map_owners_found[pt] = owners_found[0];
1897  else
1898  // Multiple owners
1899  map_owners_guessed[pt] = owners_found;
1900  }
1901 
1902  std::tuple<std::vector<std::vector<unsigned int>>,
1903  std::map<unsigned int, unsigned int>,
1904  std::map<unsigned int, std::vector<unsigned int>>>
1905  output_tuple;
1906 
1907  std::get<0>(output_tuple) = point_owners;
1908  std::get<1>(output_tuple) = map_owners_found;
1909  std::get<2>(output_tuple) = map_owners_guessed;
1910 
1911  return output_tuple;
1912  }
1913 
1914 
1915 
1916  template <int dim, int spacedim>
1917  std::vector<
1918  std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1920  {
1921  std::vector<
1922  std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1923  vertex_to_cell_map(triangulation.n_vertices());
1925  cell = triangulation.begin_active(),
1926  endc = triangulation.end();
1927  for (; cell != endc; ++cell)
1928  for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
1929  vertex_to_cell_map[cell->vertex_index(i)].insert(cell);
1930 
1931  // Take care of hanging nodes
1932  cell = triangulation.begin_active();
1933  for (; cell != endc; ++cell)
1934  {
1935  for (unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell; ++i)
1936  {
1937  if ((cell->at_boundary(i) == false) &&
1938  (cell->neighbor(i)->active()))
1939  {
1941  adjacent_cell = cell->neighbor(i);
1942  for (unsigned int j = 0;
1943  j < GeometryInfo<dim>::vertices_per_face;
1944  ++j)
1945  vertex_to_cell_map[cell->face(i)->vertex_index(j)].insert(
1946  adjacent_cell);
1947  }
1948  }
1949 
1950  // in 3d also loop over the edges
1951  if (dim == 3)
1952  {
1953  for (unsigned int i = 0; i < GeometryInfo<dim>::lines_per_cell; ++i)
1954  if (cell->line(i)->has_children())
1955  // the only place where this vertex could have been
1956  // hiding is on the mid-edge point of the edge we
1957  // are looking at
1958  vertex_to_cell_map[cell->line(i)->child(0)->vertex_index(1)]
1959  .insert(cell);
1960  }
1961  }
1962 
1963  return vertex_to_cell_map;
1964  }
1965 
1966 
1967 
1968  template <int dim, int spacedim>
1969  std::map<unsigned int, types::global_vertex_index>
1972  {
1973  std::map<unsigned int, types::global_vertex_index>
1974  local_to_global_vertex_index;
1975 
1976 #ifndef DEAL_II_WITH_MPI
1977 
1978  // without MPI, this function doesn't make sense because on cannot
1979  // use parallel::distributed::Triangulation in any meaningful
1980  // way
1981  (void)triangulation;
1982  Assert(false,
1983  ExcMessage("This function does not make any sense "
1984  "for parallel::distributed::Triangulation "
1985  "objects if you do not have MPI enabled."));
1986 
1987 #else
1988 
1989  using active_cell_iterator =
1991  const std::vector<std::set<active_cell_iterator>> vertex_to_cell =
1992  vertex_to_cell_map(triangulation);
1993 
1994  // Create a local index for the locally "owned" vertices
1995  types::global_vertex_index next_index = 0;
1996  unsigned int max_cellid_size = 0;
1997  std::set<std::pair<types::subdomain_id, types::global_vertex_index>>
1998  vertices_added;
1999  std::map<types::subdomain_id, std::set<unsigned int>> vertices_to_recv;
2000  std::map<types::subdomain_id,
2001  std::vector<std::tuple<types::global_vertex_index,
2003  std::string>>>
2004  vertices_to_send;
2005  active_cell_iterator cell = triangulation.begin_active(),
2006  endc = triangulation.end();
2007  std::set<active_cell_iterator> missing_vert_cells;
2008  std::set<unsigned int> used_vertex_index;
2009  for (; cell != endc; ++cell)
2010  {
2011  if (cell->is_locally_owned())
2012  {
2013  for (unsigned int i = 0; i < GeometryInfo<dim>::vertices_per_cell;
2014  ++i)
2015  {
2016  types::subdomain_id lowest_subdomain_id = cell->subdomain_id();
2017  typename std::set<active_cell_iterator>::iterator
2018  adjacent_cell = vertex_to_cell[cell->vertex_index(i)].begin(),
2019  end_adj_cell = vertex_to_cell[cell->vertex_index(i)].end();
2020  for (; adjacent_cell != end_adj_cell; ++adjacent_cell)
2021  lowest_subdomain_id =
2022  std::min(lowest_subdomain_id,
2023  (*adjacent_cell)->subdomain_id());
2024 
2025  // See if I "own" this vertex
2026  if (lowest_subdomain_id == cell->subdomain_id())
2027  {
2028  // Check that the vertex we are working on a vertex that has
2029  // not be dealt with yet
2030  if (used_vertex_index.find(cell->vertex_index(i)) ==
2031  used_vertex_index.end())
2032  {
2033  // Set the local index
2034  local_to_global_vertex_index[cell->vertex_index(i)] =
2035  next_index++;
2036 
2037  // Store the information that will be sent to the
2038  // adjacent cells on other subdomains
2039  adjacent_cell =
2040  vertex_to_cell[cell->vertex_index(i)].begin();
2041  for (; adjacent_cell != end_adj_cell; ++adjacent_cell)
2042  if ((*adjacent_cell)->subdomain_id() !=
2043  cell->subdomain_id())
2044  {
2045  std::pair<types::subdomain_id,
2046  types::global_vertex_index>
2047  tmp((*adjacent_cell)->subdomain_id(),
2048  cell->vertex_index(i));
2049  if (vertices_added.find(tmp) ==
2050  vertices_added.end())
2051  {
2052  vertices_to_send[(*adjacent_cell)
2053  ->subdomain_id()]
2054  .emplace_back(i,
2055  cell->vertex_index(i),
2056  cell->id().to_string());
2057  if (cell->id().to_string().size() >
2058  max_cellid_size)
2059  max_cellid_size =
2060  cell->id().to_string().size();
2061  vertices_added.insert(tmp);
2062  }
2063  }
2064  used_vertex_index.insert(cell->vertex_index(i));
2065  }
2066  }
2067  else
2068  {
2069  // We don't own the vertex so we will receive its global
2070  // index
2071  vertices_to_recv[lowest_subdomain_id].insert(
2072  cell->vertex_index(i));
2073  missing_vert_cells.insert(cell);
2074  }
2075  }
2076  }
2077 
2078  // Some hanging nodes are vertices of ghost cells. They need to be
2079  // received.
2080  if (cell->is_ghost())
2081  {
2082  for (unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell; ++i)
2083  {
2084  if (cell->at_boundary(i) == false)
2085  {
2086  if (cell->neighbor(i)->active())
2087  {
2088  typename Triangulation<dim,
2089  spacedim>::active_cell_iterator
2090  adjacent_cell = cell->neighbor(i);
2091  if ((adjacent_cell->is_locally_owned()))
2092  {
2093  types::subdomain_id adj_subdomain_id =
2094  adjacent_cell->subdomain_id();
2095  if (cell->subdomain_id() < adj_subdomain_id)
2096  for (unsigned int j = 0;
2097  j < GeometryInfo<dim>::vertices_per_face;
2098  ++j)
2099  {
2100  vertices_to_recv[cell->subdomain_id()].insert(
2101  cell->face(i)->vertex_index(j));
2102  missing_vert_cells.insert(cell);
2103  }
2104  }
2105  }
2106  }
2107  }
2108  }
2109  }
2110 
2111  // Get the size of the largest CellID string
2112  max_cellid_size =
2113  Utilities::MPI::max(max_cellid_size, triangulation.get_communicator());
2114 
2115  // Make indices global by getting the number of vertices owned by each
2116  // processors and shifting the indices accordingly
2117  const unsigned int n_cpu =
2119  std::vector<types::global_vertex_index> indices(n_cpu);
2120  int ierr = MPI_Allgather(&next_index,
2121  1,
2122  DEAL_II_VERTEX_INDEX_MPI_TYPE,
2123  indices.data(),
2124  1,
2125  DEAL_II_VERTEX_INDEX_MPI_TYPE,
2126  triangulation.get_communicator());
2127  AssertThrowMPI(ierr);
2128  Assert(indices.begin() + triangulation.locally_owned_subdomain() <
2129  indices.end(),
2130  ExcInternalError());
2131  const types::global_vertex_index shift =
2132  std::accumulate(indices.begin(),
2133  indices.begin() + triangulation.locally_owned_subdomain(),
2135 
2136  std::map<unsigned int, types::global_vertex_index>::iterator
2137  global_index_it = local_to_global_vertex_index.begin(),
2138  global_index_end = local_to_global_vertex_index.end();
2139  for (; global_index_it != global_index_end; ++global_index_it)
2140  global_index_it->second += shift;
2141 
2142  // In a first message, send the global ID of the vertices and the local
2143  // positions in the cells. In a second messages, send the cell ID as a
2144  // resize string. This is done in two messages so that types are not mixed
2145 
2146  // Send the first message
2147  std::vector<std::vector<types::global_vertex_index>> vertices_send_buffers(
2148  vertices_to_send.size());
2149  std::vector<MPI_Request> first_requests(vertices_to_send.size());
2150  typename std::map<types::subdomain_id,
2151  std::vector<std::tuple<types::global_vertex_index,
2153  std::string>>>::iterator
2154  vert_to_send_it = vertices_to_send.begin(),
2155  vert_to_send_end = vertices_to_send.end();
2156  for (unsigned int i = 0; vert_to_send_it != vert_to_send_end;
2157  ++vert_to_send_it, ++i)
2158  {
2159  int destination = vert_to_send_it->first;
2160  const unsigned int n_vertices = vert_to_send_it->second.size();
2161  const int buffer_size = 2 * n_vertices;
2162  vertices_send_buffers[i].resize(buffer_size);
2163 
2164  // fill the buffer
2165  for (unsigned int j = 0; j < n_vertices; ++j)
2166  {
2167  vertices_send_buffers[i][2 * j] =
2168  std::get<0>(vert_to_send_it->second[j]);
2169  vertices_send_buffers[i][2 * j + 1] =
2170  local_to_global_vertex_index[std::get<1>(
2171  vert_to_send_it->second[j])];
2172  }
2173 
2174  // Send the message
2175  ierr = MPI_Isend(&vertices_send_buffers[i][0],
2176  buffer_size,
2177  DEAL_II_VERTEX_INDEX_MPI_TYPE,
2178  destination,
2179  0,
2180  triangulation.get_communicator(),
2181  &first_requests[i]);
2182  AssertThrowMPI(ierr);
2183  }
2184 
2185  // Receive the first message
2186  std::vector<std::vector<types::global_vertex_index>> vertices_recv_buffers(
2187  vertices_to_recv.size());
2188  typename std::map<types::subdomain_id, std::set<unsigned int>>::iterator
2189  vert_to_recv_it = vertices_to_recv.begin(),
2190  vert_to_recv_end = vertices_to_recv.end();
2191  for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
2192  ++vert_to_recv_it, ++i)
2193  {
2194  int source = vert_to_recv_it->first;
2195  const unsigned int n_vertices = vert_to_recv_it->second.size();
2196  const int buffer_size = 2 * n_vertices;
2197  vertices_recv_buffers[i].resize(buffer_size);
2198 
2199  // Receive the message
2200  ierr = MPI_Recv(&vertices_recv_buffers[i][0],
2201  buffer_size,
2202  DEAL_II_VERTEX_INDEX_MPI_TYPE,
2203  source,
2204  0,
2205  triangulation.get_communicator(),
2206  MPI_STATUS_IGNORE);
2207  AssertThrowMPI(ierr);
2208  }
2209 
2210 
2211  // Send second message
2212  std::vector<std::vector<char>> cellids_send_buffers(
2213  vertices_to_send.size());
2214  std::vector<MPI_Request> second_requests(vertices_to_send.size());
2215  vert_to_send_it = vertices_to_send.begin();
2216  for (unsigned int i = 0; vert_to_send_it != vert_to_send_end;
2217  ++vert_to_send_it, ++i)
2218  {
2219  int destination = vert_to_send_it->first;
2220  const unsigned int n_vertices = vert_to_send_it->second.size();
2221  const int buffer_size = max_cellid_size * n_vertices;
2222  cellids_send_buffers[i].resize(buffer_size);
2223 
2224  // fill the buffer
2225  unsigned int pos = 0;
2226  for (unsigned int j = 0; j < n_vertices; ++j)
2227  {
2228  std::string cell_id = std::get<2>(vert_to_send_it->second[j]);
2229  for (unsigned int k = 0; k < max_cellid_size; ++k, ++pos)
2230  {
2231  if (k < cell_id.size())
2232  cellids_send_buffers[i][pos] = cell_id[k];
2233  // if necessary fill up the reserved part of the buffer with an
2234  // invalid value
2235  else
2236  cellids_send_buffers[i][pos] = '-';
2237  }
2238  }
2239 
2240  // Send the message
2241  ierr = MPI_Isend(&cellids_send_buffers[i][0],
2242  buffer_size,
2243  MPI_CHAR,
2244  destination,
2245  0,
2246  triangulation.get_communicator(),
2247  &second_requests[i]);
2248  AssertThrowMPI(ierr);
2249  }
2250 
2251  // Receive the second message
2252  std::vector<std::vector<char>> cellids_recv_buffers(
2253  vertices_to_recv.size());
2254  vert_to_recv_it = vertices_to_recv.begin();
2255  for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
2256  ++vert_to_recv_it, ++i)
2257  {
2258  int source = vert_to_recv_it->first;
2259  const unsigned int n_vertices = vert_to_recv_it->second.size();
2260  const int buffer_size = max_cellid_size * n_vertices;
2261  cellids_recv_buffers[i].resize(buffer_size);
2262 
2263  // Receive the message
2264  ierr = MPI_Recv(&cellids_recv_buffers[i][0],
2265  buffer_size,
2266  MPI_CHAR,
2267  source,
2268  0,
2269  triangulation.get_communicator(),
2270  MPI_STATUS_IGNORE);
2271  AssertThrowMPI(ierr);
2272  }
2273 
2274 
2275  // Match the data received with the required vertices
2276  vert_to_recv_it = vertices_to_recv.begin();
2277  for (unsigned int i = 0; vert_to_recv_it != vert_to_recv_end;
2278  ++i, ++vert_to_recv_it)
2279  {
2280  for (unsigned int j = 0; j < vert_to_recv_it->second.size(); ++j)
2281  {
2282  const unsigned int local_pos_recv = vertices_recv_buffers[i][2 * j];
2283  const types::global_vertex_index global_id_recv =
2284  vertices_recv_buffers[i][2 * j + 1];
2285  const std::string cellid_recv(
2286  &cellids_recv_buffers[i][max_cellid_size * j],
2287  &cellids_recv_buffers[i][max_cellid_size * j] + max_cellid_size);
2288  bool found = false;
2289  typename std::set<active_cell_iterator>::iterator
2290  cell_set_it = missing_vert_cells.begin(),
2291  end_cell_set = missing_vert_cells.end();
2292  for (; (found == false) && (cell_set_it != end_cell_set);
2293  ++cell_set_it)
2294  {
2295  typename std::set<active_cell_iterator>::iterator
2296  candidate_cell =
2297  vertex_to_cell[(*cell_set_it)->vertex_index(i)].begin(),
2298  end_cell =
2299  vertex_to_cell[(*cell_set_it)->vertex_index(i)].end();
2300  for (; candidate_cell != end_cell; ++candidate_cell)
2301  {
2302  std::string current_cellid =
2303  (*candidate_cell)->id().to_string();
2304  current_cellid.resize(max_cellid_size, '-');
2305  if (current_cellid.compare(cellid_recv) == 0)
2306  {
2307  local_to_global_vertex_index
2308  [(*candidate_cell)->vertex_index(local_pos_recv)] =
2309  global_id_recv;
2310  found = true;
2311 
2312  break;
2313  }
2314  }
2315  }
2316  }
2317  }
2318 #endif
2319 
2320  return local_to_global_vertex_index;
2321  }
2322 
2323 
2324 
2325  template <int dim, int spacedim>
2326  void
2328  const Triangulation<dim, spacedim> &triangulation,
2329  DynamicSparsityPattern & cell_connectivity)
2330  {
2331  cell_connectivity.reinit(triangulation.n_active_cells(),
2332  triangulation.n_active_cells());
2333 
2334  // create a map pair<lvl,idx> -> SparsityPattern index
2335  // TODO: we are no longer using user_indices for this because we can get
2336  // pointer/index clashes when saving/restoring them. The following approach
2337  // works, but this map can get quite big. Not sure about more efficient
2338  // solutions.
2339  std::map<std::pair<unsigned int, unsigned int>, unsigned int> indexmap;
2340  for (typename ::internal::
2341  ActiveCellIterator<dim, spacedim, Triangulation<dim, spacedim>>::type
2342  cell = triangulation.begin_active();
2343  cell != triangulation.end();
2344  ++cell)
2345  indexmap[std::pair<unsigned int, unsigned int>(cell->level(),
2346  cell->index())] =
2347  cell->active_cell_index();
2348 
2349  // next loop over all cells and their neighbors to build the sparsity
2350  // pattern. note that it's a bit hard to enter all the connections when a
2351  // neighbor has children since we would need to find out which of its
2352  // children is adjacent to the current cell. this problem can be omitted
2353  // if we only do something if the neighbor has no children -- in that case
2354  // it is either on the same or a coarser level than we are. in return, we
2355  // have to add entries in both directions for both cells
2356  for (typename ::internal::
2357  ActiveCellIterator<dim, spacedim, Triangulation<dim, spacedim>>::type
2358  cell = triangulation.begin_active();
2359  cell != triangulation.end();
2360  ++cell)
2361  {
2362  const unsigned int index = cell->active_cell_index();
2363  cell_connectivity.add(index, index);
2364  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
2365  if ((cell->at_boundary(f) == false) &&
2366  (cell->neighbor(f)->has_children() == false))
2367  {
2368  unsigned int other_index =
2369  indexmap
2370  .find(std::pair<unsigned int, unsigned int>(
2371  cell->neighbor(f)->level(), cell->neighbor(f)->index()))
2372  ->second;
2373  cell_connectivity.add(index, other_index);
2374  cell_connectivity.add(other_index, index);
2375  }
2376  }
2377  }
2378 
2379 
2380 
2381  template <int dim, int spacedim>
2382  void
2384  const Triangulation<dim, spacedim> &triangulation,
2385  DynamicSparsityPattern & cell_connectivity)
2386  {
2387  std::vector<std::vector<unsigned int>> vertex_to_cell(
2388  triangulation.n_vertices());
2390  triangulation.begin_active();
2391  cell != triangulation.end();
2392  ++cell)
2393  {
2394  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
2395  vertex_to_cell[cell->vertex_index(v)].push_back(
2396  cell->active_cell_index());
2397  }
2398 
2399  cell_connectivity.reinit(triangulation.n_active_cells(),
2400  triangulation.n_active_cells());
2402  triangulation.begin_active();
2403  cell != triangulation.end();
2404  ++cell)
2405  {
2406  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
2407  for (unsigned int n = 0;
2408  n < vertex_to_cell[cell->vertex_index(v)].size();
2409  ++n)
2410  cell_connectivity.add(cell->active_cell_index(),
2411  vertex_to_cell[cell->vertex_index(v)][n]);
2412  }
2413  }
2414 
2415 
2416  template <int dim, int spacedim>
2417  void
2419  const Triangulation<dim, spacedim> &triangulation,
2420  const unsigned int level,
2421  DynamicSparsityPattern & cell_connectivity)
2422  {
2423  std::vector<std::vector<unsigned int>> vertex_to_cell(
2424  triangulation.n_vertices());
2425  for (typename Triangulation<dim, spacedim>::cell_iterator cell =
2426  triangulation.begin(level);
2427  cell != triangulation.end(level);
2428  ++cell)
2429  {
2430  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
2431  vertex_to_cell[cell->vertex_index(v)].push_back(cell->index());
2432  }
2433 
2434  cell_connectivity.reinit(triangulation.n_cells(level),
2435  triangulation.n_cells(level));
2436  for (typename Triangulation<dim, spacedim>::cell_iterator cell =
2437  triangulation.begin(level);
2438  cell != triangulation.end(level);
2439  ++cell)
2440  {
2441  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
2442  for (unsigned int n = 0;
2443  n < vertex_to_cell[cell->vertex_index(v)].size();
2444  ++n)
2445  cell_connectivity.add(cell->index(),
2446  vertex_to_cell[cell->vertex_index(v)][n]);
2447  }
2448  }
2449 
2450 
2451 
2452  template <int dim, int spacedim>
2453  void
2454  partition_triangulation(const unsigned int n_partitions,
2455  Triangulation<dim, spacedim> & triangulation,
2456  const SparsityTools::Partitioner partitioner)
2457  {
2458  std::vector<unsigned int> cell_weights;
2459 
2460  // Get cell weighting if a signal has been attached to the triangulation
2461  if (!triangulation.signals.cell_weight.empty())
2462  {
2463  cell_weights.resize(triangulation.n_active_cells(),
2464  std::numeric_limits<unsigned int>::max());
2465 
2466  unsigned int c = 0;
2468  cell = triangulation.begin_active(),
2469  endc = triangulation.end();
2470  for (; cell != endc; ++cell, ++c)
2471  cell_weights[c] = triangulation.signals.cell_weight(
2473  }
2474 
2475  // Call the other more general function
2476  partition_triangulation(n_partitions,
2477  cell_weights,
2478  triangulation,
2479  partitioner);
2480  }
2481 
2482 
2483 
2484  template <int dim, int spacedim>
2485  void
2486  partition_triangulation(const unsigned int n_partitions,
2487  const std::vector<unsigned int> &cell_weights,
2488  Triangulation<dim, spacedim> & triangulation,
2489  const SparsityTools::Partitioner partitioner)
2490  {
2492  &triangulation) == nullptr),
2493  ExcMessage("Objects of type parallel::distributed::Triangulation "
2494  "are already partitioned implicitly and can not be "
2495  "partitioned again explicitly."));
2496  Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
2497 
2498  // check for an easy return
2499  if (n_partitions == 1)
2500  {
2501  for (typename ::internal::ActiveCellIterator<
2502  dim,
2503  spacedim,
2504  Triangulation<dim, spacedim>>::type cell =
2505  triangulation.begin_active();
2506  cell != triangulation.end();
2507  ++cell)
2508  cell->set_subdomain_id(0);
2509  return;
2510  }
2511 
2512  // we decompose the domain by first
2513  // generating the connection graph of all
2514  // cells with their neighbors, and then
2515  // passing this graph off to METIS.
2516  // finally defer to the other function for
2517  // partitioning and assigning subdomain ids
2518  DynamicSparsityPattern cell_connectivity;
2519  get_face_connectivity_of_cells(triangulation, cell_connectivity);
2520 
2521  SparsityPattern sp_cell_connectivity;
2522  sp_cell_connectivity.copy_from(cell_connectivity);
2523  partition_triangulation(n_partitions,
2524  cell_weights,
2525  sp_cell_connectivity,
2526  triangulation,
2527  partitioner);
2528  }
2529 
2530 
2531 
2532  template <int dim, int spacedim>
2533  void
2534  partition_triangulation(const unsigned int n_partitions,
2535  const SparsityPattern & cell_connection_graph,
2536  Triangulation<dim, spacedim> &triangulation,
2537  const SparsityTools::Partitioner partitioner)
2538  {
2539  std::vector<unsigned int> cell_weights;
2540 
2541  // Get cell weighting if a signal has been attached to the triangulation
2542  if (!triangulation.signals.cell_weight.empty())
2543  {
2544  cell_weights.resize(triangulation.n_active_cells(),
2545  std::numeric_limits<unsigned int>::max());
2546 
2547  unsigned int c = 0;
2549  cell = triangulation.begin_active(),
2550  endc = triangulation.end();
2551  for (; cell != endc; ++cell, ++c)
2552  cell_weights[c] = triangulation.signals.cell_weight(
2554  }
2555 
2556  // Call the other more general function
2557  partition_triangulation(n_partitions,
2558  cell_weights,
2559  cell_connection_graph,
2560  triangulation,
2561  partitioner);
2562  }
2563 
2564 
2565 
2566  template <int dim, int spacedim>
2567  void
2568  partition_triangulation(const unsigned int n_partitions,
2569  const std::vector<unsigned int> &cell_weights,
2570  const SparsityPattern & cell_connection_graph,
2571  Triangulation<dim, spacedim> &triangulation,
2572  const SparsityTools::Partitioner partitioner)
2573  {
2575  &triangulation) == nullptr),
2576  ExcMessage("Objects of type parallel::distributed::Triangulation "
2577  "are already partitioned implicitly and can not be "
2578  "partitioned again explicitly."));
2579  Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
2580  Assert(cell_connection_graph.n_rows() == triangulation.n_active_cells(),
2581  ExcMessage("Connectivity graph has wrong size"));
2582  Assert(cell_connection_graph.n_cols() == triangulation.n_active_cells(),
2583  ExcMessage("Connectivity graph has wrong size"));
2584 
2585  // check for an easy return
2586  if (n_partitions == 1)
2587  {
2588  for (typename ::internal::ActiveCellIterator<
2589  dim,
2590  spacedim,
2591  Triangulation<dim, spacedim>>::type cell =
2592  triangulation.begin_active();
2593  cell != triangulation.end();
2594  ++cell)
2595  cell->set_subdomain_id(0);
2596  return;
2597  }
2598 
2599  // partition this connection graph and get
2600  // back a vector of indices, one per degree
2601  // of freedom (which is associated with a
2602  // cell)
2603  std::vector<unsigned int> partition_indices(triangulation.n_active_cells());
2604  SparsityTools::partition(cell_connection_graph,
2605  cell_weights,
2606  n_partitions,
2607  partition_indices,
2608  partitioner);
2609 
2610  // finally loop over all cells and set the
2611  // subdomain ids
2612  for (typename ::internal::
2613  ActiveCellIterator<dim, spacedim, Triangulation<dim, spacedim>>::type
2614  cell = triangulation.begin_active();
2615  cell != triangulation.end();
2616  ++cell)
2617  cell->set_subdomain_id(partition_indices[cell->active_cell_index()]);
2618  }
2619 
2620 
2621  namespace
2622  {
2626  template <class IT>
2627  void
2628  set_subdomain_id_in_zorder_recursively(IT cell,
2629  unsigned int & current_proc_idx,
2630  unsigned int & current_cell_idx,
2631  const unsigned int n_active_cells,
2632  const unsigned int n_partitions)
2633  {
2634  if (cell->active())
2635  {
2636  while (
2637  current_cell_idx >=
2638  floor((long)n_active_cells * (current_proc_idx + 1) / n_partitions))
2639  ++current_proc_idx;
2640  cell->set_subdomain_id(current_proc_idx);
2641  ++current_cell_idx;
2642  }
2643  else
2644  {
2645  for (unsigned int n = 0; n < cell->n_children(); ++n)
2646  set_subdomain_id_in_zorder_recursively(cell->child(n),
2647  current_proc_idx,
2648  current_cell_idx,
2649  n_active_cells,
2650  n_partitions);
2651  }
2652  }
2653  } // namespace
2654 
2655  template <int dim, int spacedim>
2656  void
2657  partition_triangulation_zorder(const unsigned int n_partitions,
2658  Triangulation<dim, spacedim> &triangulation)
2659  {
2661  &triangulation) == nullptr),
2662  ExcMessage("Objects of type parallel::distributed::Triangulation "
2663  "are already partitioned implicitly and can not be "
2664  "partitioned again explicitly."));
2665  Assert(n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
2666 
2667  // check for an easy return
2668  if (n_partitions == 1)
2669  {
2670  for (typename ::internal::ActiveCellIterator<
2671  dim,
2672  spacedim,
2673  Triangulation<dim, spacedim>>::type cell =
2674  triangulation.begin_active();
2675  cell != triangulation.end();
2676  ++cell)
2677  cell->set_subdomain_id(0);
2678  return;
2679  }
2680 
2681  // Duplicate the coarse cell reordoring
2682  // as done in p4est
2683  std::vector<types::global_dof_index> coarse_cell_to_p4est_tree_permutation;
2684  std::vector<types::global_dof_index> p4est_tree_to_coarse_cell_permutation;
2685 
2686  DynamicSparsityPattern cell_connectivity;
2688  0,
2689  cell_connectivity);
2690  coarse_cell_to_p4est_tree_permutation.resize(triangulation.n_cells(0));
2691  SparsityTools::reorder_hierarchical(cell_connectivity,
2692  coarse_cell_to_p4est_tree_permutation);
2693 
2694  p4est_tree_to_coarse_cell_permutation =
2695  Utilities::invert_permutation(coarse_cell_to_p4est_tree_permutation);
2696 
2697  unsigned int current_proc_idx = 0;
2698  unsigned int current_cell_idx = 0;
2699  const unsigned int n_active_cells = triangulation.n_active_cells();
2700 
2701  // set subdomain id for active cell descendants
2702  // of each coarse cell in permuted order
2703  for (unsigned int idx = 0; idx < triangulation.n_cells(0); ++idx)
2704  {
2705  const unsigned int coarse_cell_idx =
2706  p4est_tree_to_coarse_cell_permutation[idx];
2707  typename Triangulation<dim, spacedim>::cell_iterator coarse_cell(
2708  &triangulation, 0, coarse_cell_idx);
2709 
2710  set_subdomain_id_in_zorder_recursively(coarse_cell,
2711  current_proc_idx,
2712  current_cell_idx,
2713  n_active_cells,
2714  n_partitions);
2715  }
2716 
2717  // if all children of a cell are active (e.g. we
2718  // have a cell that is refined once and no part
2719  // is refined further), p4est places all of them
2720  // on the same processor. The new owner will be
2721  // the processor with the largest number of children
2722  // (ties are broken by picking the lower rank).
2723  // Duplicate this logic here.
2724  {
2726  cell = triangulation.begin(),
2727  endc = triangulation.end();
2728  for (; cell != endc; ++cell)
2729  {
2730  if (cell->active())
2731  continue;
2732  bool all_children_active = true;
2733  std::map<unsigned int, unsigned int> map_cpu_n_cells;
2734  for (unsigned int n = 0; n < cell->n_children(); ++n)
2735  if (!cell->child(n)->active())
2736  {
2737  all_children_active = false;
2738  break;
2739  }
2740  else
2741  ++map_cpu_n_cells[cell->child(n)->subdomain_id()];
2742 
2743  if (!all_children_active)
2744  continue;
2745 
2746  unsigned int new_owner = cell->child(0)->subdomain_id();
2747  for (std::map<unsigned int, unsigned int>::iterator it =
2748  map_cpu_n_cells.begin();
2749  it != map_cpu_n_cells.end();
2750  ++it)
2751  if (it->second > map_cpu_n_cells[new_owner])
2752  new_owner = it->first;
2753 
2754  for (unsigned int n = 0; n < cell->n_children(); ++n)
2755  cell->child(n)->set_subdomain_id(new_owner);
2756  }
2757  }
2758  }
2759 
2760 
2761  template <int dim, int spacedim>
2762  void
2764  {
2765  unsigned int n_levels = triangulation.n_levels();
2766  for (int lvl = n_levels - 1; lvl >= 0; --lvl)
2767  {
2769  cell = triangulation.begin(lvl),
2770  endc = triangulation.end(lvl);
2771  for (; cell != endc; ++cell)
2772  {
2773  if (!cell->has_children())
2774  cell->set_level_subdomain_id(cell->subdomain_id());
2775  else
2776  {
2777  Assert(cell->child(0)->level_subdomain_id() !=
2779  ExcInternalError());
2780  cell->set_level_subdomain_id(
2781  cell->child(0)->level_subdomain_id());
2782  }
2783  }
2784  }
2785  }
2786 
2787 
2788  template <int dim, int spacedim>
2789  void
2791  std::vector<types::subdomain_id> & subdomain)
2792  {
2793  Assert(subdomain.size() == triangulation.n_active_cells(),
2794  ExcDimensionMismatch(subdomain.size(),
2795  triangulation.n_active_cells()));
2797  triangulation.begin_active();
2798  cell != triangulation.end();
2799  ++cell)
2800  subdomain[cell->active_cell_index()] = cell->subdomain_id();
2801  }
2802 
2803 
2804 
2805  template <int dim, int spacedim>
2806  unsigned int
2808  const Triangulation<dim, spacedim> &triangulation,
2809  const types::subdomain_id subdomain)
2810  {
2811  unsigned int count = 0;
2813  triangulation.begin_active();
2814  cell != triangulation.end();
2815  ++cell)
2816  if (cell->subdomain_id() == subdomain)
2817  ++count;
2818 
2819  return count;
2820  }
2821 
2822 
2823 
2824  template <int dim, int spacedim>
2825  std::vector<bool>
2827  {
2828  // start with all vertices
2829  std::vector<bool> locally_owned_vertices =
2830  triangulation.get_used_vertices();
2831 
2832  // if the triangulation is distributed, eliminate those that
2833  // are owned by other processors -- either because the vertex is
2834  // on an artificial cell, or because it is on a ghost cell with
2835  // a smaller subdomain
2838  *>(&triangulation))
2839  for (typename ::internal::ActiveCellIterator<
2840  dim,
2841  spacedim,
2842  Triangulation<dim, spacedim>>::type cell =
2843  triangulation.begin_active();
2844  cell != triangulation.end();
2845  ++cell)
2846  if (cell->is_artificial() ||
2847  (cell->is_ghost() &&
2848  (cell->subdomain_id() < tr->locally_owned_subdomain())))
2849  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell;
2850  ++v)
2851  locally_owned_vertices[cell->vertex_index(v)] = false;
2852 
2853  return locally_owned_vertices;
2854  }
2855 
2856 
2857 
2858  namespace
2859  {
2860  template <int dim, int spacedim>
2861  double
2863  const Mapping<dim, spacedim> &mapping)
2864  {
2865  const auto vertices = mapping.get_vertices(cell);
2866  switch (dim)
2867  {
2868  case 1:
2869  return (vertices[1] - vertices[0]).norm();
2870  case 2:
2871  return std::max((vertices[3] - vertices[0]).norm(),
2872  (vertices[2] - vertices[1]).norm());
2873  case 3:
2874  return std::max(std::max((vertices[7] - vertices[0]).norm(),
2875  (vertices[6] - vertices[1]).norm()),
2876  std::max((vertices[2] - vertices[5]).norm(),
2877  (vertices[3] - vertices[4]).norm()));
2878  default:
2879  Assert(false, ExcNotImplemented());
2880  return -1e10;
2881  }
2882  }
2883  } // namespace
2884 
2885 
2886  template <int dim, int spacedim>
2887  double
2889  const Mapping<dim, spacedim> & mapping)
2890  {
2891  double min_diameter = std::numeric_limits<double>::max();
2892  for (const auto &cell : triangulation.active_cell_iterators())
2893  if (!cell->is_artificial())
2894  min_diameter =
2895  std::min(min_diameter, diameter<dim, spacedim>(cell, mapping));
2896 
2897  double global_min_diameter = 0;
2898 
2899 #ifdef DEAL_II_WITH_MPI
2900  if (const parallel::Triangulation<dim, spacedim> *p_tria =
2901  dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
2902  &triangulation))
2903  global_min_diameter =
2904  Utilities::MPI::min(min_diameter, p_tria->get_communicator());
2905  else
2906 #endif
2907  global_min_diameter = min_diameter;
2908 
2909  return global_min_diameter;
2910  }
2911 
2912 
2913 
2914  template <int dim, int spacedim>
2915  double
2917  const Mapping<dim, spacedim> & mapping)
2918  {
2919  double max_diameter = 0.;
2920  for (const auto &cell : triangulation.active_cell_iterators())
2921  if (!cell->is_artificial())
2922  max_diameter = std::max(max_diameter, diameter(cell, mapping));
2923 
2924  double global_max_diameter = 0;
2925 
2926 #ifdef DEAL_II_WITH_MPI
2927  if (const parallel::Triangulation<dim, spacedim> *p_tria =
2928  dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
2929  &triangulation))
2930  global_max_diameter =
2931  Utilities::MPI::max(max_diameter, p_tria->get_communicator());
2932  else
2933 #endif
2934  global_max_diameter = max_diameter;
2935 
2936  return global_max_diameter;
2937  }
2938 
2939 
2940 
2941  namespace internal
2942  {
2943  namespace FixUpDistortedChildCells
2944  {
2945  // compute the mean square
2946  // deviation of the alternating
2947  // forms of the children of the
2948  // given object from that of
2949  // the object itself. for
2950  // objects with
2951  // structdim==spacedim, the
2952  // alternating form is the
2953  // determinant of the jacobian,
2954  // whereas for faces with
2955  // structdim==spacedim-1, the
2956  // alternating form is the
2957  // (signed and scaled) normal
2958  // vector
2959  //
2960  // this average square
2961  // deviation is computed for an
2962  // object where the center node
2963  // has been replaced by the
2964  // second argument to this
2965  // function
2966  template <typename Iterator, int spacedim>
2967  double
2968  objective_function(const Iterator & object,
2969  const Point<spacedim> &object_mid_point)
2970  {
2971  const unsigned int structdim =
2972  Iterator::AccessorType::structure_dimension;
2973  Assert(spacedim == Iterator::AccessorType::dimension,
2974  ExcInternalError());
2975 
2976  // everything below is wrong
2977  // if not for the following
2978  // condition
2979  Assert(object->refinement_case() ==
2981  ExcNotImplemented());
2982  // first calculate the
2983  // average alternating form
2984  // for the parent cell/face
2987  Tensor<spacedim - structdim, spacedim>
2988  parent_alternating_forms[GeometryInfo<structdim>::vertices_per_cell];
2989 
2990  for (unsigned int i = 0; i < GeometryInfo<structdim>::vertices_per_cell;
2991  ++i)
2992  parent_vertices[i] = object->vertex(i);
2993 
2995  parent_vertices, parent_alternating_forms);
2996 
2997  const Tensor<spacedim - structdim, spacedim>
2998  average_parent_alternating_form =
2999  std::accumulate(parent_alternating_forms,
3000  parent_alternating_forms +
3003 
3004  // now do the same
3005  // computation for the
3006  // children where we use the
3007  // given location for the
3008  // object mid point instead of
3009  // the one the triangulation
3010  // currently reports
3014  Tensor<spacedim - structdim, spacedim> child_alternating_forms
3017 
3018  for (unsigned int c = 0; c < object->n_children(); ++c)
3019  for (unsigned int i = 0;
3020  i < GeometryInfo<structdim>::vertices_per_cell;
3021  ++i)
3022  child_vertices[c][i] = object->child(c)->vertex(i);
3023 
3024  // replace mid-object
3025  // vertex. note that for
3026  // child i, the mid-object
3027  // vertex happens to have the
3028  // number
3029  // max_children_per_cell-i
3030  for (unsigned int c = 0; c < object->n_children(); ++c)
3031  child_vertices[c][GeometryInfo<structdim>::max_children_per_cell - c -
3032  1] = object_mid_point;
3033 
3034  for (unsigned int c = 0; c < object->n_children(); ++c)
3036  child_vertices[c], child_alternating_forms[c]);
3037 
3038  // on a uniformly refined
3039  // hypercube object, the child
3040  // alternating forms should
3041  // all be smaller by a factor
3042  // of 2^structdim than the
3043  // ones of the parent. as a
3044  // consequence, we'll use the
3045  // squared deviation from
3046  // this ideal value as an
3047  // objective function
3048  double objective = 0;
3049  for (unsigned int c = 0; c < object->n_children(); ++c)
3050  for (unsigned int i = 0;
3051  i < GeometryInfo<structdim>::vertices_per_cell;
3052  ++i)
3053  objective +=
3054  (child_alternating_forms[c][i] -
3055  average_parent_alternating_form / std::pow(2., 1. * structdim))
3056  .norm_square();
3057 
3058  return objective;
3059  }
3060 
3061 
3067  template <typename Iterator>
3069  get_face_midpoint(const Iterator & object,
3070  const unsigned int f,
3071  std::integral_constant<int, 1>)
3072  {
3073  return object->vertex(f);
3074  }
3075 
3076 
3077 
3083  template <typename Iterator>
3085  get_face_midpoint(const Iterator & object,
3086  const unsigned int f,
3087  std::integral_constant<int, 2>)
3088  {
3089  return object->line(f)->center();
3090  }
3091 
3092 
3093 
3099  template <typename Iterator>
3101  get_face_midpoint(const Iterator & object,
3102  const unsigned int f,
3103  std::integral_constant<int, 3>)
3104  {
3105  return object->face(f)->center();
3106  }
3107 
3108 
3109 
3132  template <typename Iterator>
3133  double
3134  minimal_diameter(const Iterator &object)
3135  {
3136  const unsigned int structdim =
3137  Iterator::AccessorType::structure_dimension;
3138 
3139  double diameter = object->diameter();
3140  for (unsigned int f = 0; f < GeometryInfo<structdim>::faces_per_cell;
3141  ++f)
3142  for (unsigned int e = f + 1;
3143  e < GeometryInfo<structdim>::faces_per_cell;
3144  ++e)
3145  diameter = std::min(
3146  diameter,
3147  get_face_midpoint(object,
3148  f,
3149  std::integral_constant<int, structdim>())
3150  .distance(get_face_midpoint(
3151  object, e, std::integral_constant<int, structdim>())));
3152 
3153  return diameter;
3154  }
3155 
3156 
3157 
3162  template <typename Iterator>
3163  bool
3164  fix_up_object(const Iterator &object)
3165  {
3166  const unsigned int structdim =
3167  Iterator::AccessorType::structure_dimension;
3168  const unsigned int spacedim = Iterator::AccessorType::space_dimension;
3169 
3170  // right now we can only deal with cells that have been refined
3171  // isotropically because that is the only case where we have a cell
3172  // mid-point that can be moved around without having to consider
3173  // boundary information
3174  Assert(object->has_children(), ExcInternalError());
3175  Assert(object->refinement_case() ==
3177  ExcNotImplemented());
3178 
3179  // get the current location of the object mid-vertex:
3180  Point<spacedim> object_mid_point = object->child(0)->vertex(
3182 
3183  // now do a few steepest descent steps to reduce the objective
3184  // function. compute the diameter in the helper function above
3185  unsigned int iteration = 0;
3186  const double diameter = minimal_diameter(object);
3187 
3188  // current value of objective function and initial delta
3189  double current_value = objective_function(object, object_mid_point);
3190  double initial_delta = 0;
3191 
3192  do
3193  {
3194  // choose a step length that is initially 1/4 of the child
3195  // objects' diameter, and a sequence whose sum does not converge
3196  // (to avoid premature termination of the iteration)
3197  const double step_length = diameter / 4 / (iteration + 1);
3198 
3199  // compute the objective function's derivative using a two-sided
3200  // difference formula with eps=step_length/10
3201  Tensor<1, spacedim> gradient;
3202  for (unsigned int d = 0; d < spacedim; ++d)
3203  {
3204  const double eps = step_length / 10;
3205 
3207  h[d] = eps / 2;
3208 
3209  gradient[d] =
3210  (objective_function(
3211  object, project_to_object(object, object_mid_point + h)) -
3212  objective_function(
3213  object, project_to_object(object, object_mid_point - h))) /
3214  eps;
3215  }
3216 
3217  // there is nowhere to go
3218  if (gradient.norm() == 0)
3219  break;
3220 
3221  // We need to go in direction -gradient. the optimal value of the
3222  // objective function is zero, so assuming that the model is
3223  // quadratic we would have to go -2*val/||gradient|| in this
3224  // direction, make sure we go at most step_length into this
3225  // direction
3226  object_mid_point -=
3227  std::min(2 * current_value / (gradient * gradient),
3228  step_length / gradient.norm()) *
3229  gradient;
3230  object_mid_point = project_to_object(object, object_mid_point);
3231 
3232  // compute current value of the objective function
3233  const double previous_value = current_value;
3234  current_value = objective_function(object, object_mid_point);
3235 
3236  if (iteration == 0)
3237  initial_delta = (previous_value - current_value);
3238 
3239  // stop if we aren't moving much any more
3240  if ((iteration >= 1) &&
3241  ((previous_value - current_value < 0) ||
3242  (std::fabs(previous_value - current_value) <
3243  0.001 * initial_delta)))
3244  break;
3245 
3246  ++iteration;
3247  }
3248  while (iteration < 20);
3249 
3250  // verify that the new
3251  // location is indeed better
3252  // than the one before. check
3253  // this by comparing whether
3254  // the minimum value of the
3255  // products of parent and
3256  // child alternating forms is
3257  // positive. for cells this
3258  // means that the
3259  // determinants have the same
3260  // sign, for faces that the
3261  // face normals of parent and
3262  // children point in the same
3263  // general direction
3264  double old_min_product, new_min_product;
3265 
3268  for (unsigned int i = 0; i < GeometryInfo<structdim>::vertices_per_cell;
3269  ++i)
3270  parent_vertices[i] = object->vertex(i);
3271 
3272  Tensor<spacedim - structdim, spacedim>
3273  parent_alternating_forms[GeometryInfo<structdim>::vertices_per_cell];
3275  parent_vertices, parent_alternating_forms);
3276 
3280 
3281  for (unsigned int c = 0; c < object->n_children(); ++c)
3282  for (unsigned int i = 0;
3283  i < GeometryInfo<structdim>::vertices_per_cell;
3284  ++i)
3285  child_vertices[c][i] = object->child(c)->vertex(i);
3286 
3287  Tensor<spacedim - structdim, spacedim> child_alternating_forms
3290 
3291  for (unsigned int c = 0; c < object->n_children(); ++c)
3293  child_vertices[c], child_alternating_forms[c]);
3294 
3295  old_min_product =
3296  child_alternating_forms[0][0] * parent_alternating_forms[0];
3297  for (unsigned int c = 0; c < object->n_children(); ++c)
3298  for (unsigned int i = 0;
3299  i < GeometryInfo<structdim>::vertices_per_cell;
3300  ++i)
3301  for (unsigned int j = 0;
3302  j < GeometryInfo<structdim>::vertices_per_cell;
3303  ++j)
3304  old_min_product = std::min<double>(old_min_product,
3305  child_alternating_forms[c][i] *
3306  parent_alternating_forms[j]);
3307 
3308  // for the new minimum value,
3309  // replace mid-object
3310  // vertex. note that for child
3311  // i, the mid-object vertex
3312  // happens to have the number
3313  // max_children_per_cell-i
3314  for (unsigned int c = 0; c < object->n_children(); ++c)
3315  child_vertices[c][GeometryInfo<structdim>::max_children_per_cell - c -
3316  1] = object_mid_point;
3317 
3318  for (unsigned int c = 0; c < object->n_children(); ++c)
3320  child_vertices[c], child_alternating_forms[c]);
3321 
3322  new_min_product =
3323  child_alternating_forms[0][0] * parent_alternating_forms[0];
3324  for (unsigned int c = 0; c < object->n_children(); ++c)
3325  for (unsigned int i = 0;
3326  i < GeometryInfo<structdim>::vertices_per_cell;
3327  ++i)
3328  for (unsigned int j = 0;
3329  j < GeometryInfo<structdim>::vertices_per_cell;
3330  ++j)
3331  new_min_product = std::min<double>(new_min_product,
3332  child_alternating_forms[c][i] *
3333  parent_alternating_forms[j]);
3334 
3335  // if new minimum value is
3336  // better than before, then set the
3337  // new mid point. otherwise
3338  // return this object as one of
3339  // those that can't apparently
3340  // be fixed
3341  if (new_min_product >= old_min_product)
3342  object->child(0)->vertex(
3344  object_mid_point;
3345 
3346  // return whether after this
3347  // operation we have an object that
3348  // is well oriented
3349  return (std::max(new_min_product, old_min_product) > 0);
3350  }
3351 
3352 
3353 
3354  void
3355  fix_up_faces(const ::Triangulation<1, 1>::cell_iterator &,
3356  std::integral_constant<int, 1>,
3357  std::integral_constant<int, 1>)
3358  {
3359  // nothing to do for the faces of cells in 1d
3360  }
3361 
3362 
3363 
3364  // possibly fix up the faces of a cell by moving around its mid-points
3365  template <int dim, int spacedim>
3366  void
3367  fix_up_faces(
3368  const typename ::Triangulation<dim, spacedim>::cell_iterator
3369  &cell,
3370  std::integral_constant<int, dim>,
3371  std::integral_constant<int, spacedim>)
3372  {
3373  // see if we first can fix up some of the faces of this object. We can
3374  // mess with faces if and only if the neighboring cell is not even
3375  // more refined than we are (since in that case the sub-faces have
3376  // themselves children that we can't move around any more). however,
3377  // the latter case shouldn't happen anyway: if the current face is
3378  // distorted but the neighbor is even more refined, then the face had
3379  // been deformed before already, and had been ignored at the time; we
3380  // should then also be able to ignore it this time as well
3381  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
3382  {
3383  Assert(cell->face(f)->has_children(), ExcInternalError());
3384  Assert(cell->face(f)->refinement_case() ==
3385  RefinementCase<dim - 1>::isotropic_refinement,
3386  ExcInternalError());
3387 
3388  bool subface_is_more_refined = false;
3389  for (unsigned int g = 0;
3390  g < GeometryInfo<dim>::max_children_per_face;
3391  ++g)
3392  if (cell->face(f)->child(g)->has_children())
3393  {
3394  subface_is_more_refined = true;
3395  break;
3396  }
3397 
3398  if (subface_is_more_refined == true)
3399  continue;
3400 
3401  // we finally know that we can do something about this face
3402  fix_up_object(cell->face(f));
3403  }
3404  }
3405  } /* namespace FixUpDistortedChildCells */
3406  } /* namespace internal */
3407 
3408 
3409  template <int dim, int spacedim>
3413  &distorted_cells,
3414  Triangulation<dim, spacedim> & /*triangulation*/)
3415  {
3416  typename Triangulation<dim, spacedim>::DistortedCellList unfixable_subset;
3417 
3418  // loop over all cells that we have to fix up
3419  for (typename std::list<
3420  typename Triangulation<dim, spacedim>::cell_iterator>::const_iterator
3421  cell_ptr = distorted_cells.distorted_cells.begin();
3422  cell_ptr != distorted_cells.distorted_cells.end();
3423  ++cell_ptr)
3424  {
3425  const typename Triangulation<dim, spacedim>::cell_iterator cell =
3426  *cell_ptr;
3427 
3428  Assert(!cell->active(),
3429  ExcMessage(
3430  "This function is only valid for a list of cells that "
3431  "have children (i.e., no cell in the list may be active)."));
3432 
3433  internal::FixUpDistortedChildCells ::fix_up_faces(
3434  cell,
3435  std::integral_constant<int, dim>(),
3436  std::integral_constant<int, spacedim>());
3437 
3438  // If possible, fix up the object.
3439  if (!internal::FixUpDistortedChildCells::fix_up_object(cell))
3440  unfixable_subset.distorted_cells.push_back(cell);
3441  }
3442 
3443  return unfixable_subset;
3444  }
3445 
3446 
3447 
3448  template <int dim, int spacedim>
3449  void
3451  const bool reset_boundary_ids)
3452  {
3453  const auto src_boundary_ids = tria.get_boundary_ids();
3454  std::vector<types::manifold_id> dst_manifold_ids(src_boundary_ids.size());
3455  auto m_it = dst_manifold_ids.begin();
3456  for (auto b : src_boundary_ids)
3457  {
3458  *m_it = static_cast<types::manifold_id>(b);
3459  ++m_it;
3460  }
3461  const std::vector<types::boundary_id> reset_boundary_id =
3462  reset_boundary_ids ?
3463  std::vector<types::boundary_id>(src_boundary_ids.size(), 0) :
3464  src_boundary_ids;
3465  map_boundary_to_manifold_ids(src_boundary_ids,
3466  dst_manifold_ids,
3467  tria,
3468  reset_boundary_id);
3469  }
3470 
3471 
3472 
3473  template <int dim, int spacedim>
3474  void
3476  const std::vector<types::boundary_id> &src_boundary_ids,
3477  const std::vector<types::manifold_id> &dst_manifold_ids,
3479  const std::vector<types::boundary_id> &reset_boundary_ids_)
3480  {
3481  AssertDimension(src_boundary_ids.size(), dst_manifold_ids.size());
3482  const auto reset_boundary_ids =
3483  reset_boundary_ids_.size() ? reset_boundary_ids_ : src_boundary_ids;
3484  AssertDimension(reset_boundary_ids.size(), src_boundary_ids.size());
3485 
3486  // in 3d, we not only have to copy boundary ids of faces, but also of edges
3487  // because we see them twice (once from each adjacent boundary face),
3488  // we cannot immediately reset their boundary ids. thus, copy first
3489  // and reset later
3490  if (dim >= 3)
3492  tria.begin_active();
3493  cell != tria.end();
3494  ++cell)
3495  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
3496  if (cell->face(f)->at_boundary())
3497  for (unsigned int e = 0; e < GeometryInfo<dim>::lines_per_face; ++e)
3498  {
3499  const auto bid = cell->face(f)->line(e)->boundary_id();
3500  const auto ind = std::find(src_boundary_ids.begin(),
3501  src_boundary_ids.end(),
3502  bid) -
3503  src_boundary_ids.begin();
3504  if ((unsigned int)ind < src_boundary_ids.size())
3505  cell->face(f)->line(e)->set_manifold_id(
3506  dst_manifold_ids[ind]);
3507  }
3508 
3509  // now do cells
3511  tria.begin_active();
3512  cell != tria.end();
3513  ++cell)
3514  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
3515  if (cell->face(f)->at_boundary())
3516  {
3517  const auto bid = cell->face(f)->boundary_id();
3518  const auto ind =
3519  std::find(src_boundary_ids.begin(), src_boundary_ids.end(), bid) -
3520  src_boundary_ids.begin();
3521 
3522  if ((unsigned int)ind < src_boundary_ids.size())
3523  {
3524  // assign the manifold id
3525  cell->face(f)->set_manifold_id(dst_manifold_ids[ind]);
3526  // then reset boundary id
3527  cell->face(f)->set_boundary_id(reset_boundary_ids[ind]);
3528  }
3529 
3530  if (dim >= 3)
3531  for (unsigned int e = 0; e < GeometryInfo<dim>::lines_per_face;
3532  ++e)
3533  {
3534  const auto bid = cell->face(f)->line(e)->boundary_id();
3535  const auto ind = std::find(src_boundary_ids.begin(),
3536  src_boundary_ids.end(),
3537  bid) -
3538  src_boundary_ids.begin();
3539  if ((unsigned int)ind < src_boundary_ids.size())
3540  cell->face(f)->line(e)->set_boundary_id(
3541  reset_boundary_ids[ind]);
3542  }
3543  }
3544  }
3545 
3546 
3547  template <int dim, int spacedim>
3548  void
3550  const bool compute_face_ids)
3551  {
3553  cell = tria.begin_active(),
3554  endc = tria.end();
3555 
3556  for (; cell != endc; ++cell)
3557  {
3558  cell->set_manifold_id(cell->material_id());
3559  if (compute_face_ids == true)
3560  {
3561  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
3562  {
3563  if (cell->at_boundary(f) == false)
3564  cell->face(f)->set_manifold_id(
3565  std::min(cell->material_id(),
3566  cell->neighbor(f)->material_id()));
3567  else
3568  cell->face(f)->set_manifold_id(cell->material_id());
3569  }
3570  }
3571  }
3572  }
3573 
3574  template <int dim, int spacedim>
3575  std::pair<unsigned int, double>
3578  {
3579  double max_ratio = 1;
3580  unsigned int index = 0;
3581 
3582  for (unsigned int i = 0; i < dim; ++i)
3583  for (unsigned int j = i + 1; j < dim; ++j)
3584  {
3585  unsigned int ax = i % dim;
3586  unsigned int next_ax = j % dim;
3587 
3588  double ratio =
3589  cell->extent_in_direction(ax) / cell->extent_in_direction(next_ax);
3590 
3591  if (ratio > max_ratio)
3592  {
3593  max_ratio = ratio;
3594  index = ax;
3595  }
3596  else if (1.0 / ratio > max_ratio)
3597  {
3598  max_ratio = 1.0 / ratio;
3599  index = next_ax;
3600  }
3601  }
3602  return std::make_pair(index, max_ratio);
3603  }
3604 
3605 
3606  template <int dim, int spacedim>
3607  void
3609  const bool isotropic,
3610  const unsigned int max_iterations)
3611  {
3612  unsigned int iter = 0;
3613  bool continue_refinement = true;
3614 
3616  cell = tria.begin_active(),
3617  endc = tria.end();
3618 
3619  while (continue_refinement && (iter < max_iterations))
3620  {
3621  if (max_iterations != numbers::invalid_unsigned_int)
3622  iter++;
3623  continue_refinement = false;
3624 
3625  for (cell = tria.begin_active(); cell != endc; ++cell)
3626  for (unsigned int j = 0; j < GeometryInfo<dim>::faces_per_cell; j++)
3627  if (cell->at_boundary(j) == false &&
3628  cell->neighbor(j)->has_children())
3629  {
3630  if (isotropic)
3631  {
3632  cell->set_refine_flag();
3633  continue_refinement = true;
3634  }
3635  else
3636  continue_refinement |= cell->flag_for_face_refinement(j);
3637  }
3638 
3640  }
3641  }
3642 
3643  template <int dim, int spacedim>
3644  void
3646  const double max_ratio,
3647  const unsigned int max_iterations)
3648  {
3649  unsigned int iter = 0;
3650  bool continue_refinement = true;
3651 
3653  cell = tria.begin_active(),
3654  endc = tria.end();
3655 
3656  while (continue_refinement && (iter < max_iterations))
3657  {
3658  iter++;
3659  continue_refinement = false;
3660  for (cell = tria.begin_active(); cell != endc; ++cell)
3661  {
3662  std::pair<unsigned int, double> info =
3663  GridTools::get_longest_direction<dim, spacedim>(cell);
3664  if (info.second > max_ratio)
3665  {
3666  cell->set_refine_flag(
3667  RefinementCase<dim>::cut_axis(info.first));
3668  continue_refinement = true;
3669  }
3670  }
3672  }
3673  }
3674 
3675 
3676  template <int dim, int spacedim>
3677  void
3679  const double limit_angle_fraction)
3680  {
3681  if (dim == 1)
3682  return; // Nothing to do
3683 
3684  // Check that we don't have hanging nodes
3686  ExcMessage("The input Triangulation cannot "
3687  "have hanging nodes."));
3688 
3689 
3690  bool has_cells_with_more_than_dim_faces_on_boundary = true;
3691  bool has_cells_with_dim_faces_on_boundary = false;
3692 
3693  unsigned int refinement_cycles = 0;
3694 
3695  while (has_cells_with_more_than_dim_faces_on_boundary)
3696  {
3697  has_cells_with_more_than_dim_faces_on_boundary = false;
3698 
3699  for (auto cell : tria.active_cell_iterators())
3700  {
3701  unsigned int boundary_face_counter = 0;
3702  for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
3703  if (cell->face(f)->at_boundary())
3704  boundary_face_counter++;
3705  if (boundary_face_counter > dim)
3706  {
3707  has_cells_with_more_than_dim_faces_on_boundary = true;
3708  break;
3709  }
3710  else if (boundary_face_counter == dim)
3711  has_cells_with_dim_faces_on_boundary = true;
3712  }
3713  if (has_cells_with_more_than_dim_faces_on_boundary)
3714  {
3715  tria.refine_global(1);
3716  refinement_cycles++;
3717  }
3718  }
3719 
3720  if (has_cells_with_dim_faces_on_boundary)
3721  {
3722  tria.refine_global(1);
3723  refinement_cycles++;
3724  }
3725  else
3726  {
3727  while (refinement_cycles > 0)
3728  {
3729  for (auto cell : tria.active_cell_iterators())
3730  cell->set_coarsen_flag();
3732  refinement_cycles--;
3733  }
3734  return;
3735  }
3736 
3737  std::vector<bool> cells_to_remove(tria.n_active_cells(), false);
3738  std::vector<Point<spacedim>> vertices = tria.get_vertices();
3739 
3740  std::vector<bool> faces_to_remove(tria.n_raw_faces(), false);
3741 
3742  std::vector<CellData<dim>> cells_to_add;
3743  SubCellData subcelldata_to_add;
3744 
3745  // Trick compiler for dimension independent things
3746  const unsigned int v0 = 0, v1 = 1, v2 = (dim > 1 ? 2 : 0),
3747  v3 = (dim > 1 ? 3 : 0);
3748 
3749  for (auto cell : tria.active_cell_iterators())
3750  {
3751  double angle_fraction = 0;
3752  unsigned int vertex_at_corner = numbers::invalid_unsigned_int;
3753 
3754  if (dim == 2)
3755  {
3757  p0[spacedim > 1 ? 1 : 0] = 1;
3759  p1[0] = 1;
3760 
3761  if (cell->face(v0)->at_boundary() && cell->face(v3)->at_boundary())
3762  {
3763  p0 = cell->vertex(v0) - cell->vertex(v2);
3764  p1 = cell->vertex(v3) - cell->vertex(v2);
3765  vertex_at_corner = v2;
3766  }
3767  else if (cell->face(v3)->at_boundary() &&
3768  cell->face(v1)->at_boundary())
3769  {
3770  p0 = cell->vertex(v2) - cell->vertex(v3);
3771  p1 = cell->vertex(v1) - cell->vertex(v3);
3772  vertex_at_corner = v3;
3773  }
3774  else if (cell->face(1)->at_boundary() &&
3775  cell->face(2)->at_boundary())
3776  {
3777  p0 = cell->vertex(v0) - cell->vertex(v1);
3778  p1 = cell->vertex(v3) - cell->vertex(v1);
3779  vertex_at_corner = v1;
3780  }
3781  else if (cell->face(2)->at_boundary() &&
3782  cell->face(0)->at_boundary())
3783  {
3784  p0 = cell->vertex(v2) - cell->vertex(v0);
3785  p1 = cell->vertex(v1) - cell->vertex(v0);
3786  vertex_at_corner = v0;
3787  }
3788  p0 /= p0.norm();
3789  p1 /= p1.norm();
3790  angle_fraction = std::acos(p0 * p1) / numbers::PI;
3791  }
3792  else
3793  {
3794  Assert(false, ExcNotImplemented());
3795  }
3796 
3797  if (angle_fraction > limit_angle_fraction)
3798  {
3799  auto flags_removal = [&](unsigned int f1,
3800  unsigned int f2,
3801  unsigned int n1,
3802  unsigned int n2) -> void {
3803  cells_to_remove[cell->active_cell_index()] = true;
3804  cells_to_remove[cell->neighbor(n1)->active_cell_index()] = true;
3805  cells_to_remove[cell->neighbor(n2)->active_cell_index()] = true;
3806 
3807  faces_to_remove[cell->face(f1)->index()] = true;
3808  faces_to_remove[cell->face(f2)->index()] = true;
3809 
3810  faces_to_remove[cell->neighbor(n1)->face(f1)->index()] = true;
3811  faces_to_remove[cell->neighbor(n2)->face(f2)->index()] = true;
3812  };
3813 
3814  auto cell_creation = [&](const unsigned int vv0,
3815  const unsigned int vv1,
3816  const unsigned int f0,
3817  const unsigned int f1,
3818 
3819  const unsigned int n0,
3820  const unsigned int v0n0,
3821  const unsigned int v1n0,
3822 
3823  const unsigned int n1,
3824  const unsigned int v0n1,
3825  const unsigned int v1n1) {
3826  CellData<dim> c1, c2;
3827  CellData<1> l1, l2;
3828 
3829  c1.vertices[v0] = cell->vertex_index(vv0);
3830  c1.vertices[v1] = cell->vertex_index(vv1);
3831  c1.vertices[v2] = cell->neighbor(n0)->vertex_index(v0n0);
3832  c1.vertices[v3] = cell->neighbor(n0)->vertex_index(v1n0);
3833 
3834  c1.manifold_id = cell->manifold_id();
3835  c1.material_id = cell->material_id();
3836 
3837  c2.vertices[v0] = cell->vertex_index(vv0);
3838  c2.vertices[v1] = cell->neighbor(n1)->vertex_index(v0n1);
3839  c2.vertices[v2] = cell->vertex_index(vv1);
3840  c2.vertices[v3] = cell->neighbor(n1)->vertex_index(v1n1);
3841 
3842  c2.manifold_id = cell->manifold_id();
3843  c2.material_id = cell->material_id();
3844 
3845  l1.vertices[0] = cell->vertex_index(vv0);
3846  l1.vertices[1] = cell->neighbor(n0)->vertex_index(v0n0);
3847 
3848  l1.boundary_id = cell->line(f0)->boundary_id();
3849  l1.manifold_id = cell->line(f0)->manifold_id();
3850  subcelldata_to_add.boundary_lines.push_back(l1);
3851 
3852  l2.vertices[0] = cell->vertex_index(vv0);
3853  l2.vertices[1] = cell->neighbor(n1)->vertex_index(v0n1);
3854 
3855  l2.boundary_id = cell->line(f1)->boundary_id();
3856  l2.manifold_id = cell->line(f1)->manifold_id();
3857  subcelldata_to_add.boundary_lines.push_back(l2);
3858 
3859  cells_to_add.push_back(c1);
3860  cells_to_add.push_back(c2);
3861  };
3862 
3863  if (dim == 2)
3864  {
3865  switch (vertex_at_corner)
3866  {
3867  case 0:
3868  flags_removal(0, 2, 3, 1);
3869  cell_creation(0, 3, 0, 2, 3, 2, 3, 1, 1, 3);
3870  break;
3871  case 1:
3872  flags_removal(1, 2, 3, 0);
3873  cell_creation(1, 2, 2, 1, 0, 0, 2, 3, 3, 2);
3874  break;
3875  case 2:
3876  flags_removal(3, 0, 1, 2);
3877  cell_creation(2, 1, 3, 0, 1, 3, 1, 2, 0, 1);
3878  break;
3879  case 3:
3880  flags_removal(3, 1, 0, 2);
3881  cell_creation(3, 0, 1, 3, 2, 1, 0, 0, 2, 0);
3882  break;
3883  }
3884  }
3885  else
3886  {
3887  Assert(false, ExcNotImplemented());
3888  }
3889  }
3890  }
3891 
3892  // if no cells need to be added, then no regularization is necessary.
3893  // Restore things as they were before this function was called.
3894  if (cells_to_add.size() == 0)
3895  {
3896  while (refinement_cycles > 0)
3897  {
3898  for (auto cell : tria.active_cell_iterators())
3899  cell->set_coarsen_flag();
3901  refinement_cycles--;
3902  }
3903  return;
3904  }
3905 
3906  // add the cells that were not marked as skipped
3907  for (auto cell : tria.active_cell_iterators())
3908  {
3909  if (cells_to_remove[cell->active_cell_index()] == false)
3910  {
3911  CellData<dim> c;
3912  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell;
3913  ++v)
3914  c.vertices[v] = cell->vertex_index(v);
3915  c.manifold_id = cell->manifold_id();
3916  c.material_id = cell->material_id();
3917  cells_to_add.push_back(c);
3918  }
3919  }
3920 
3921  // Face counter for both dim == 2 and dim == 3
3923  face = tria.begin_active_face(),
3924  endf = tria.end_face();
3925  for (; face != endf; ++face)
3926  if ((face->at_boundary() ||
3927  face->manifold_id() != numbers::invalid_manifold_id) &&
3928  faces_to_remove[face->index()] == false)
3929  {
3930  for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_face; ++l)
3931  {
3932  CellData<1> line;
3933  if (dim == 2)
3934  {
3935  for (unsigned int v = 0;
3936  v < GeometryInfo<1>::vertices_per_cell;
3937  ++v)
3938  line.vertices[v] = face->vertex_index(v);
3939  line.boundary_id = face->boundary_id();
3940  line.manifold_id = face->manifold_id();
3941  }
3942  else
3943  {
3944  for (unsigned int v = 0;
3945  v < GeometryInfo<1>::vertices_per_cell;
3946  ++v)
3947  line.vertices[v] = face->line(l)->vertex_index(v);
3948  line.boundary_id = face->line(l)->boundary_id();
3949  line.manifold_id = face->line(l)->manifold_id();
3950  }
3951  subcelldata_to_add.boundary_lines.push_back(line);
3952  }
3953  if (dim == 3)
3954  {
3955  CellData<2> quad;
3956  for (unsigned int v = 0; v < GeometryInfo<2>::vertices_per_cell;
3957  ++v)
3958  quad.vertices[v] = face->vertex_index(v);
3959  quad.boundary_id = face->boundary_id();
3960  quad.manifold_id = face->manifold_id();
3961  subcelldata_to_add.boundary_quads.push_back(quad);
3962  }
3963  }
3965  cells_to_add,
3966  subcelldata_to_add);
3968 
3969  // Save manifolds
3970  auto manifold_ids = tria.get_manifold_ids();
3971  std::map<types::manifold_id, std::unique_ptr<Manifold<dim, spacedim>>>
3972  manifolds;
3973  // Set manifolds in new Triangulation
3974  for (auto manifold_id : manifold_ids)
3975  if (manifold_id != numbers::invalid_manifold_id)
3976  manifolds[manifold_id] = tria.get_manifold(manifold_id).clone();
3977 
3978  tria.clear();
3979 
3980  tria.create_triangulation(vertices, cells_to_add, subcelldata_to_add);
3981 
3982  // Restore manifolds
3983  for (auto manifold_id : manifold_ids)
3984  if (manifold_id != numbers::invalid_manifold_id)
3985  tria.set_manifold(manifold_id, *manifolds[manifold_id]);
3986  }
3987 
3988 
3989 
3990  template <int dim, int spacedim>
3991 #ifndef DOXYGEN
3992  std::tuple<
3993  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
3994  std::vector<std::vector<Point<dim>>>,
3995  std::vector<std::vector<unsigned int>>>
3996 #else
3997  return_type
3998 #endif
4000  const Cache<dim, spacedim> & cache,
4001  const std::vector<Point<spacedim>> &points,
4003  &cell_hint)
4004  {
4005  // How many points are here?
4006  const unsigned int np = points.size();
4007 
4008  std::tuple<
4009  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
4010  std::vector<std::vector<Point<dim>>>,
4011  std::vector<std::vector<unsigned int>>>
4012  cell_qpoint_map;
4013 
4014  // Now the easy case.
4015  if (np == 0)
4016  return cell_qpoint_map;
4017 
4018  // We begin by finding the cell/transform of the first point
4019  std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
4020  Point<dim>>
4021  my_pair;
4022  if (cell_hint.state() == IteratorState::valid)
4023  my_pair =
4024  GridTools::find_active_cell_around_point(cache, points[0], cell_hint);
4025  else
4026  my_pair = GridTools::find_active_cell_around_point(cache, points[0]);
4027 
4028  std::get<0>(cell_qpoint_map).emplace_back(my_pair.first);
4029  std::get<1>(cell_qpoint_map).emplace_back(1, my_pair.second);
4030  std::get<2>(cell_qpoint_map).emplace_back(1, 0);
4031 
4032  // Now the second easy case.
4033  if (np == 1)
4034  return cell_qpoint_map;
4035  // Computing the cell center and diameter
4036  Point<spacedim> cell_center = std::get<0>(cell_qpoint_map)[0]->center();
4037  double cell_diameter = std::get<0>(cell_qpoint_map)[0]->diameter() *
4038  (0.5 + std::numeric_limits<double>::epsilon());
4039 
4040  // Cycle over all points left
4041  for (unsigned int p = 1; p < np; ++p)
4042  {
4043  // Checking if the point is close to the cell center, in which
4044  // case calling find active cell with a cell hint
4045  if (cell_center.distance(points[p]) < cell_diameter)
4047  cache, points[p], std::get<0>(cell_qpoint_map).back());
4048  else
4049  my_pair = GridTools::find_active_cell_around_point(cache, points[p]);
4050 
4051  // Assuming the cell is probably the last cell added
4052  if (my_pair.first == std::get<0>(cell_qpoint_map).back())
4053  {
4054  // Found in the last cell: adding the data
4055  std::get<1>(cell_qpoint_map).back().emplace_back(my_pair.second);
4056  std::get<2>(cell_qpoint_map).back().emplace_back(p);
4057  }
4058  else
4059  {
4060  // Check if it is in another cell already found
4061  typename std::vector<typename Triangulation<dim, spacedim>::
4062  active_cell_iterator>::iterator cells_it =
4063  std::find(std::get<0>(cell_qpoint_map).begin(),
4064  std::get<0>(cell_qpoint_map).end() - 1,
4065  my_pair.first);
4066 
4067  if (cells_it == std::get<0>(cell_qpoint_map).end() - 1)
4068  {
4069  // Cell not found: adding a new cell
4070  std::get<0>(cell_qpoint_map).emplace_back(my_pair.first);
4071  std::get<1>(cell_qpoint_map).emplace_back(1, my_pair.second);
4072  std::get<2>(cell_qpoint_map).emplace_back(1, p);
4073  // Updating center and radius of the cell
4074  cell_center = std::get<0>(cell_qpoint_map).back()->center();
4075  cell_diameter =
4076  std::get<0>(cell_qpoint_map).back()->diameter() *
4077  (0.5 + std::numeric_limits<double>::epsilon());
4078  }
4079  else
4080  {
4081  unsigned int current_cell =
4082  cells_it - std::get<0>(cell_qpoint_map).begin();
4083  // Cell found: just adding the point index and qpoint to the
4084  // list
4085  std::get<1>(cell_qpoint_map)[current_cell].emplace_back(
4086  my_pair.second);
4087  std::get<2>(cell_qpoint_map)[current_cell].emplace_back(p);
4088  }
4089  }
4090  }
4091 
4092  // Debug Checking
4093  Assert(std::get<0>(cell_qpoint_map).size() ==
4094  std::get<2>(cell_qpoint_map).size(),
4095  ExcDimensionMismatch(std::get<0>(cell_qpoint_map).size(),
4096  std::get<2>(cell_qpoint_map).size()));
4097 
4098  Assert(std::get<0>(cell_qpoint_map).size() ==
4099  std::get<1>(cell_qpoint_map).size(),
4100  ExcDimensionMismatch(std::get<0>(cell_qpoint_map).size(),
4101  std::get<1>(cell_qpoint_map).size()));
4102 
4103 #ifdef DEBUG
4104  unsigned int c = std::get<0>(cell_qpoint_map).size();
4105  unsigned int qps = 0;
4106  // The number of points in all
4107  // the cells must be the same as
4108  // the number of points we
4109  // started off from.
4110  for (unsigned int n = 0; n < c; ++n)
4111  {
4112  Assert(std::get<1>(cell_qpoint_map)[n].size() ==
4113  std::get<2>(cell_qpoint_map)[n].size(),
4114  ExcDimensionMismatch(std::get<1>(cell_qpoint_map)[n].size(),
4115  std::get<2>(cell_qpoint_map)[n].size()));
4116  qps += std::get<1>(cell_qpoint_map)[n].size();
4117  }
4118  Assert(qps == np, ExcDimensionMismatch(qps, np));
4119 #endif
4120 
4121  return cell_qpoint_map;
4122  }
4123 
4124 
4125 
4126  namespace internal
4127  {
4128  // Functions are needed for distributed compute point locations
4129  namespace distributed_cptloc
4130  {
4131  // Hash function for cells; needed for unordered maps/multimaps
4132  template <int dim, int spacedim>
4133  struct cell_hash
4134  {
4135  std::size_t
4136  operator()(
4138  const
4139  {
4140  // Return active cell index, which is faster than CellId to compute
4141  return k->active_cell_index();
4142  }
4143  };
4144 
4145 
4146 
4147  // Compute point locations; internal version which returns an unordered
4148  // map The algorithm is the same as GridTools::compute_point_locations
4149  template <int dim, int spacedim>
4150  std::unordered_map<
4152  std::pair<std::vector<Point<dim>>, std::vector<unsigned int>>,
4153  cell_hash<dim, spacedim>>
4154  compute_point_locations_unmap(
4155  const GridTools::Cache<dim, spacedim> &cache,
4156  const std::vector<Point<spacedim>> & points)
4157  {
4158  // How many points are here?
4159  const unsigned int np = points.size();
4160  // Creating the output tuple
4161  std::unordered_map<
4162  typename Triangulation<dim, spacedim>::active_cell_iterator,
4163  std::pair<std::vector<Point<dim>>, std::vector<unsigned int>>,
4164  cell_hash<dim, spacedim>>
4165  cell_qpoint_map;
4166 
4167  // Now the easy case.
4168  if (np == 0)
4169  return cell_qpoint_map;
4170  // We begin by finding the cell/transform of the first point
4171  auto my_pair =
4172  GridTools::find_active_cell_around_point(cache, points[0]);
4173 
4174  auto last_cell = cell_qpoint_map.emplace(
4175  std::make_pair(my_pair.first,
4176  std::make_pair(std::vector<Point<dim>>{my_pair.second},
4177  std::vector<unsigned int>{0})));
4178  // Now the second easy case.
4179  if (np == 1)
4180  return cell_qpoint_map;
4181  // Computing the cell center and diameter
4182  Point<spacedim> cell_center = my_pair.first->center();
4183  double cell_diameter = my_pair.first->diameter() *
4184  (0.5 + std::numeric_limits<double>::epsilon());
4185 
4186  // Cycle over all points left
4187  for (unsigned int p = 1; p < np; ++p)
4188  {
4189  // Checking if the point is close to the cell center, in which
4190  // case calling find active cell with a cell hint
4191  if (cell_center.distance(points[p]) < cell_diameter)
4193  cache, points[p], last_cell.first->first);
4194  else
4195  my_pair =
4196  GridTools::find_active_cell_around_point(cache, points[p]);
4197 
4198  if (last_cell.first->first == my_pair.first)
4199  {
4200  last_cell.first->second.first.emplace_back(my_pair.second);
4201  last_cell.first->second.second.emplace_back(p);
4202  }
4203  else
4204  {
4205  // Check if it is in another cell already found
4206  last_cell = cell_qpoint_map.emplace(std::make_pair(
4207  my_pair.first,
4208  std::make_pair(std::vector<Point<dim>>{my_pair.second},
4209  std::vector<unsigned int>{p})));
4210 
4211  if (last_cell.second == false)
4212  {
4213  // Cell already present: adding the new point
4214  last_cell.first->second.first.emplace_back(my_pair.second);
4215  last_cell.first->second.second.emplace_back(p);
4216  }
4217  else
4218  {
4219  // New cell was added, updating center and diameter
4220  cell_center = my_pair.first->center();
4221  cell_diameter =
4222  my_pair.first->diameter() *
4223  (0.5 + std::numeric_limits<double>::epsilon());
4224  }
4225  }
4226  }
4227 
4228 #ifdef DEBUG
4229  unsigned int qps = 0;
4230  // The number of points in all
4231  // the cells must be the same as
4232  // the number of points we
4233  // started off from.
4234  for (const auto &m : cell_qpoint_map)
4235  {
4236  Assert(m.second.second.size() == m.second.first.size(),
4237  ExcDimensionMismatch(m.second.second.size(),
4238  m.second.first.size()));
4239  qps += m.second.second.size();
4240  }
4241  Assert(qps == np, ExcDimensionMismatch(qps, np));
4242 #endif
4243  return cell_qpoint_map;
4244  }
4245 
4246 
4247 
4248  // Merging the output means to add data to a previous output, here
4249  // contained in output unmap: if the cell is already present: add
4250  // information about new points if the cell is not present: add the cell
4251  // with all information
4252  //
4253  // Notice we call "information" the data associated with a point of the
4254  // sort: cell containing it, transformed point on reference cell, index,
4255  // rank of the owner etc.
4256  template <int dim, int spacedim>
4257  void
4258  merge_cptloc_outputs(
4259  std::unordered_map<
4260  typename Triangulation<dim, spacedim>::active_cell_iterator,
4261  std::tuple<std::vector<Point<dim>>,
4262  std::vector<unsigned int>,
4263  std::vector<Point<spacedim>>,
4264  std::vector<unsigned int>>,
4265  cell_hash<dim, spacedim>> &output_unmap,
4266  const std::vector<
4267  typename Triangulation<dim, spacedim>::active_cell_iterator>
4268  & in_cells,
4269  const std::vector<std::vector<Point<dim>>> & in_qpoints,
4270  const std::vector<std::vector<unsigned int>> & in_maps,
4271  const std::vector<std::vector<Point<spacedim>>> &in_points,
4272  const unsigned int in_rank)
4273  {
4274  // Adding cells, one by one
4275  for (unsigned int c = 0; c < in_cells.size(); ++c)
4276  {
4277  // Attempt to add a new cell with its relative data
4278  auto current_c = output_unmap.emplace(
4279  std::make_pair(in_cells[c],
4280  std::make_tuple(in_qpoints[c],
4281  in_maps[c],
4282  in_points[c],
4283  std::vector<unsigned int>(
4284  in_points[c].size(), in_rank))));
4285  // If the flag is false no new cell was added:
4286  if (current_c.second == false)
4287  {
4288  // Cell in output map at current_c.first:
4289  // Adding the information to it
4290  auto &cell_qpts = std::get<0>(current_c.first->second);
4291  auto &cell_maps = std::get<1>(current_c.first->second);
4292  auto &cell_pts = std::get<2>(current_c.first->second);
4293  auto &cell_ranks = std::get<3>(current_c.first->second);
4294  cell_qpts.insert(cell_qpts.end(),
4295  in_qpoints[c].begin(),
4296  in_qpoints[c].end());
4297  cell_maps.insert(cell_maps.end(),
4298  in_maps[c].begin(),
4299  in_maps[c].end());
4300  cell_pts.insert(cell_pts.end(),
4301  in_points[c].begin(),
4302  in_points[c].end());
4303  std::vector<unsigned int> ranks_tmp(in_points[c].size(),
4304  in_rank);
4305  cell_ranks.insert(cell_ranks.end(),
4306  ranks_tmp.begin(),
4307  ranks_tmp.end());
4308  }
4309  }
4310  }
4311 
4312 
4313 
4314  // This function initializes the output by calling compute point locations
4315  // on local points; vector containing points which are probably local.
4316  // Its output is then sorted in the following manner:
4317  // - output unmap: points, with relative information, inside locally onwed
4318  // cells,
4319  // - ghost loc pts: points, with relative information, inside ghost cells,
4320  // - classified pts: vector of all points returned in output map and ghost
4321  // loc pts
4322  // (these are stored as indices)
4323  template <int dim, int spacedim>
4324  void
4325  compute_and_classify_points(
4326  const GridTools::Cache<dim, spacedim> &cache,
4327  const std::vector<Point<spacedim>> & local_points,
4328  const std::vector<unsigned int> & local_points_idx,
4329  std::unordered_map<
4330  typename Triangulation<dim, spacedim>::active_cell_iterator,
4331  std::tuple<std::vector<Point<dim>>,
4332  std::vector<unsigned int>,
4333  std::vector<Point<spacedim>>,
4334  std::vector<unsigned int>>,
4335  cell_hash<dim, spacedim>> &output_unmap,
4336  std::map<unsigned int,
4337  std::tuple<std::vector<CellId>,
4338  std::vector<std::vector<Point<dim>>>,
4339  std::vector<std::vector<unsigned int>>,
4340  std::vector<std::vector<Point<spacedim>>>>>
4341  & ghost_loc_pts,
4342  std::vector<unsigned int> &classified_pts)
4343  {
4344  auto cpt_loc_pts = compute_point_locations_unmap(cache, local_points);
4345 
4346  // Alayzing the output discarding artificial cell
4347  // and storing in the proper container locally owned and ghost cells
4348  for (auto const &cell_tuples : cpt_loc_pts)
4349  {
4350  auto &cell_loc = cell_tuples.first;
4351  auto &q_loc = std::get<0>(cell_tuples.second);
4352  auto &indices_loc = std::get<1>(cell_tuples.second);
4353  if (cell_loc->is_locally_owned())
4354  {
4355  // Point inside locally owned cell: storing all its data
4356  std::vector<Point<spacedim>> cell_points(indices_loc.size());
4357  std::vector<unsigned int> cell_points_idx(indices_loc.size());
4358  for (unsigned int i = 0; i < indices_loc.size(); ++i)
4359  {
4360  // Adding the point to the cell points
4361  cell_points[i] = local_points[indices_loc[i]];
4362 
4363  // Storing the index: notice indices loc refer to the local
4364  // points vector, but we need to return the index with
4365  // respect of the points owned by the current process
4366  cell_points_idx[i] = local_points_idx[indices_loc[i]];
4367  classified_pts.emplace_back(
4368  local_points_idx[indices_loc[i]]);
4369  }
4370  output_unmap.emplace(
4371  std::make_pair(cell_loc,
4372  std::make_tuple(q_loc,
4373  cell_points_idx,
4374  cell_points,
4375  std::vector<unsigned int>(
4376  indices_loc.size(),
4377  cell_loc->subdomain_id()))));
4378  }
4379  else if (cell_loc->is_ghost())
4380  {
4381  // Point inside ghost cell: storing all its information and
4382  // preparing it to be sent
4383  std::vector<Point<spacedim>> cell_points(indices_loc.size());
4384  std::vector<unsigned int> cell_points_idx(indices_loc.size());
4385  for (unsigned int i = 0; i < indices_loc.size(); ++i)
4386  {
4387  cell_points[i] = local_points[indices_loc[i]];
4388  cell_points_idx[i] = local_points_idx[indices_loc[i]];
4389  classified_pts.emplace_back(
4390  local_points_idx[indices_loc[i]]);
4391  }
4392  // Each key of the following map represent a process,
4393  // each mapped value is a tuple containing the information to be
4394  // sent: preparing the output for the owner, which has rank
4395  // subdomain id
4396  auto &map_tuple_owner = ghost_loc_pts[cell_loc->subdomain_id()];
4397  // To identify the cell on the other process we use the cell id
4398  std::get<0>(map_tuple_owner).emplace_back(cell_loc->id());
4399  std::get<1>(map_tuple_owner).emplace_back(q_loc);
4400  std::get<2>(map_tuple_owner).emplace_back(cell_points_idx);
4401  std::get<3>(map_tuple_owner).emplace_back(cell_points);
4402  }
4403  // else: the cell is artificial, nothing to do
4404  }
4405  }
4406 
4407 
4408 
4409  // Given the map obtained from a communication, where the key is rank and
4410  // the mapped value is a pair of (points,indices), calls compute point
4411  // locations; its output is then merged with output tuple if check_owned
4412  // is set to true only points lying inside locally onwed cells shall be
4413  // merged, otherwise all points shall be merged.
4414  template <int dim, int spacedim>
4415  void
4416  compute_and_merge_from_map(
4417  const GridTools::Cache<dim, spacedim> & cache,
4418  const std::map<unsigned int,
4419  std::pair<std::vector<Point<spacedim>>,
4420  std::vector<unsigned int>>> &map_pts,
4421  std::unordered_map<
4422  typename Triangulation<dim, spacedim>::active_cell_iterator,
4423  std::tuple<std::vector<Point<dim>>,
4424  std::vector<unsigned int>,
4425  std::vector<Point<spacedim>>,
4426  std::vector<unsigned int>>,
4427  cell_hash<dim, spacedim>> &output_unmap,
4428  const bool & check_owned)
4429  {
4430  bool no_check = !check_owned;
4431 
4432  // rank and points is a pair: first rank, then a pair of vectors
4433  // (points, indices)
4434  for (auto const &rank_and_points : map_pts)
4435  {
4436  // Rewriting the contents of the map in human readable format
4437  const auto &received_process = rank_and_points.first;
4438  const auto &received_points = rank_and_points.second.first;
4439  const auto &received_map = rank_and_points.second.second;
4440 
4441  // Initializing the vectors needed to store the result of compute
4442  // point location
4443  std::vector<
4444  typename Triangulation<dim, spacedim>::active_cell_iterator>
4445  in_cell;
4446  std::vector<std::vector<Point<dim>>> in_qpoints;
4447  std::vector<std::vector<unsigned int>> in_maps;
4448  std::vector<std::vector<Point<spacedim>>> in_points;
4449 
4450  auto cpt_loc_pts =
4451  compute_point_locations_unmap(cache,
4452  rank_and_points.second.first);
4453  for (const auto &map_c_pt_idx : cpt_loc_pts)
4454  {
4455  // Human-readable variables:
4456  const auto &proc_cell = map_c_pt_idx.first;
4457  const auto &proc_qpoints = map_c_pt_idx.second.first;
4458  const auto &proc_maps = map_c_pt_idx.second.second;
4459 
4460  // This is stored either if we're not checking if the cell is
4461  // owned or if the cell is locally owned
4462  if (no_check || proc_cell->is_locally_owned())
4463  {
4464  in_cell.emplace_back(proc_cell);
4465  in_qpoints.emplace_back(proc_qpoints);
4466  // The other two vectors need to be built
4467  unsigned int loc_size = proc_qpoints.size();
4468  std::vector<unsigned int> cell_maps(loc_size);
4469  std::vector<Point<spacedim>> cell_points(loc_size);
4470  for (unsigned int pt = 0; pt < loc_size; ++pt)
4471  {
4472  cell_maps[pt] = received_map[proc_maps[pt]];
4473  cell_points[pt] = received_points[proc_maps[pt]];
4474  }
4475  in_maps.emplace_back(cell_maps);
4476  in_points.emplace_back(cell_points);
4477  }
4478  }
4479 
4480  // Merge everything from the current process
4481  internal::distributed_cptloc::merge_cptloc_outputs(
4482  output_unmap,
4483  in_cell,
4484  in_qpoints,
4485  in_maps,
4486  in_points,
4487  received_process);
4488  }
4489  }
4490  } // namespace distributed_cptloc
4491  } // namespace internal
4492 
4493 
4494 
4495  template <int dim, int spacedim>
4496 #ifndef DOXYGEN
4497  std::tuple<
4498  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
4499  std::vector<std::vector<Point<dim>>>,
4500  std::vector<std::vector<unsigned int>>,
4501  std::vector<std::vector<Point<spacedim>>>,
4502  std::vector<std::vector<unsigned int>>>
4503 #else
4504  return_type
4505 #endif
4507  const GridTools::Cache<dim, spacedim> & cache,
4508  const std::vector<Point<spacedim>> & local_points,
4509  const std::vector<std::vector<BoundingBox<spacedim>>> &global_bboxes)
4510  {
4511 #ifndef DEAL_II_WITH_MPI
4512  (void)cache;
4513  (void)local_points;
4514  (void)global_bboxes;
4515  Assert(false,
4516  ExcMessage(
4517  "GridTools::distributed_compute_point_locations() requires MPI."));
4518  std::tuple<
4519  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
4520  std::vector<std::vector<Point<dim>>>,
4521  std::vector<std::vector<unsigned int>>,
4522  std::vector<std::vector<Point<spacedim>>>,
4523  std::vector<std::vector<unsigned int>>>
4524  tup;
4525  return tup;
4526 #else
4527  // Recovering the mpi communicator used to create the triangulation
4528  const auto &tria_mpi =
4529  dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
4530  &cache.get_triangulation());
4531  // If the dynamic cast failed we can't recover the mpi communicator:
4532  // throwing an assertion error
4533  Assert(
4534  tria_mpi,
4535  ExcMessage(
4536  "GridTools::distributed_compute_point_locations() requires a parallel triangulation."));
4537  auto mpi_communicator = tria_mpi->get_communicator();
4538  // Preparing the output tuple
4539  std::tuple<
4540  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>,
4541  std::vector<std::vector<Point<dim>>>,
4542  std::vector<std::vector<unsigned int>>,
4543  std::vector<std::vector<Point<spacedim>>>,
4544  std::vector<std::vector<unsigned int>>>
4545  output_tuple;
4546 
4547  // Preparing the temporary unordered map
4548  std::unordered_map<
4550  std::tuple<std::vector<Point<dim>>,
4551  std::vector<unsigned int>,
4552  std::vector<Point<spacedim>>,
4553  std::vector<unsigned int>>,
4554  internal::distributed_cptloc::cell_hash<dim, spacedim>>
4555  temporary_unmap;
4556 
4557  // Step 1 (part 1): Using the bounding boxes to guess the owner of each
4558  // points in local_points
4559  unsigned int my_rank = Utilities::MPI::this_mpi_process(mpi_communicator);
4560 
4561  // Using global bounding boxes to guess/find owner/s of each point
4562  std::tuple<std::vector<std::vector<unsigned int>>,
4563  std::map<unsigned int, unsigned int>,
4564  std::map<unsigned int, std::vector<unsigned int>>>
4565  guessed_points;
4566  guessed_points = GridTools::guess_point_owner(global_bboxes, local_points);
4567 
4568  // Preparing to call compute point locations on points which are/might be
4569  // local
4570  const auto &guess_loc_idx = std::get<0>(guessed_points)[my_rank];
4571  const unsigned int n_local_guess = guess_loc_idx.size();
4572  // Vector containing points which are probably local
4573  std::vector<Point<spacedim>> guess_local_pts(n_local_guess);
4574  for (unsigned int i = 0; i < n_local_guess; ++i)
4575  guess_local_pts[i] = local_points[guess_loc_idx[i]];
4576 
4577  // Preparing the map with data on points lying on locally owned cells
4578  std::map<unsigned int,
4579  std::tuple<std::vector<CellId>,
4580  std::vector<std::vector<Point<dim>>>,
4581  std::vector<std::vector<unsigned int>>,
4582  std::vector<std::vector<Point<spacedim>>>>>
4583  ghost_loc_pts;
4584  // Vector containing indices of points lying either on locally owned
4585  // cells or ghost cells, to avoid computing them more than once
4586  std::vector<unsigned int> classified_pts;
4587 
4588  // Thread used to call compute point locations on guess local pts
4589  Threads::Task<void> cpt_loc_tsk = Threads::new_task(
4590  &internal::distributed_cptloc::compute_and_classify_points<dim, spacedim>,
4591  cache,
4592  guess_local_pts,
4593  guess_loc_idx,
4594  temporary_unmap,
4595  ghost_loc_pts,
4596  classified_pts);
4597 
4598  // Step 1 (part 2): communicate point which are owned by a certain process
4599  // Preparing the map with points whose owner is known with certainty:
4600  const auto &other_owned_idx = std::get<1>(guessed_points);
4601  std::map<unsigned int,
4602  std::pair<std::vector<Point<spacedim>>, std::vector<unsigned int>>>
4603  other_owned_pts;
4604 
4605  for (const auto &indices : other_owned_idx)
4606  if (indices.second != my_rank)
4607  {
4608  // Finding/adding in the map the current process
4609  auto &current_pts = other_owned_pts[indices.second];
4610  // Indices.first is the index of the considered point in local points
4611  current_pts.first.emplace_back(local_points[indices.first]);
4612  current_pts.second.emplace_back(indices.first);
4613  }
4614 
4615  // Communicating the points whose owner is sure
4616  auto owned_rank_pts =
4617  Utilities::MPI::some_to_some(mpi_communicator, other_owned_pts);
4618  // Waiting for part 1 to finish to avoid concurrency problems
4619  cpt_loc_tsk.join();
4620 
4621  // Step 2 (part 1): compute received points which are owned
4622  Threads::Task<void> owned_pts_tsk = Threads::new_task(
4623  &internal::distributed_cptloc::compute_and_merge_from_map<dim, spacedim>,
4624  cache,
4625  owned_rank_pts,
4626  temporary_unmap,
4627  false);
4628 
4629  // Step 2 (part 2): communicate info on points lying on ghost cells
4630  auto cpt_ghost =
4631  Utilities::MPI::some_to_some(mpi_communicator, ghost_loc_pts);
4632 
4633  // Step 3: construct vectors containing uncertain points i.e. those whose
4634  // owner is known among few guesses The maps goes from rank of the probable
4635  // owner to a pair of vectors: the first containing the points, the second
4636  // containing the ranks in the current process
4637  std::map<unsigned int,
4638  std::pair<std::vector<Point<spacedim>>, std::vector<unsigned int>>>
4639  other_check_pts;
4640 
4641  // This map goes from the point index to a vector of
4642  // ranks probable owners
4643  const std::map<unsigned int, std::vector<unsigned int>> &other_check_idx =
4644  std::get<2>(guessed_points);
4645 
4646  // Points in classified pts need not to be communicated;
4647  // sorting the array classified pts in order to use
4648  // binary search when checking if the points needs to be
4649  // communicated
4650  // Notice classified pts is a vector of integer indexes
4651  std::sort(classified_pts.begin(), classified_pts.end());
4652 
4653  for (const auto &pt_to_guesses : other_check_idx)
4654  {
4655  const auto &point_idx = pt_to_guesses.first;
4656  const auto &probable_owners_rks = pt_to_guesses.second;
4657  if (!std::binary_search(classified_pts.begin(),
4658  classified_pts.end(),
4659  point_idx))
4660  // The point wasn't found in ghost or locally owned cells: adding it
4661  // to the map
4662  for (unsigned int i = 0; i < probable_owners_rks.size(); ++i)
4663  if (probable_owners_rks[i] != my_rank)
4664  {
4665  // add to the data for process probable_owners_rks[i]
4666  auto &current_pts = other_check_pts[probable_owners_rks[i]];
4667  // The point local_points[point_idx]
4668  current_pts.first.emplace_back(local_points[point_idx]);
4669  // and its index in the current process
4670  current_pts.second.emplace_back(point_idx);
4671  }
4672  }
4673 
4674  // Step 4: send around uncertain points
4675  auto check_pts =
4676  Utilities::MPI::some_to_some(mpi_communicator, other_check_pts);
4677  // Before proceeding, merging threads to avoid concurrency problems
4678  owned_pts_tsk.join();
4679 
4680  // Step 5: add the received ghost cell data to output
4681  for (const auto &rank_vals : cpt_ghost)
4682  {
4683  // Transforming CellsIds into Tria iterators
4684  const auto &cell_ids = std::get<0>(rank_vals.second);
4685  unsigned int n_cells = cell_ids.size();
4686  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
4687  cell_iter(n_cells);
4688  for (unsigned int c = 0; c < n_cells; ++c)
4689  cell_iter[c] = cell_ids[c].to_cell(cache.get_triangulation());
4690 
4691  internal::distributed_cptloc::merge_cptloc_outputs(
4692  temporary_unmap,
4693  cell_iter,
4694  std::get<1>(rank_vals.second),
4695  std::get<2>(rank_vals.second),
4696  std::get<3>(rank_vals.second),
4697  rank_vals.first);
4698  }
4699 
4700  // Step 6: use compute point locations on the uncertain points and
4701  // merge output
4702  internal::distributed_cptloc::compute_and_merge_from_map(cache,
4703  check_pts,
4704  temporary_unmap,
4705  true);
4706 
4707  // Copying data from the unordered map to the tuple
4708  // and returning output
4709  unsigned int size_output = temporary_unmap.size();
4710  auto &out_cells = std::get<0>(output_tuple);
4711  auto &out_qpoints = std::get<1>(output_tuple);
4712  auto &out_maps = std::get<2>(output_tuple);
4713  auto &out_points = std::get<3>(output_tuple);
4714  auto &out_ranks = std::get<4>(output_tuple);
4715 
4716  out_cells.resize(size_output);
4717  out_qpoints.resize(size_output);
4718  out_maps.resize(size_output);
4719  out_points.resize(size_output);
4720  out_ranks.resize(size_output);
4721 
4722  unsigned int c = 0;
4723  for (const auto &rank_and_tuple : temporary_unmap)
4724  {
4725  out_cells[c] = rank_and_tuple.first;
4726  out_qpoints[c] = std::get<0>(rank_and_tuple.second);
4727  out_maps[c] = std::get<1>(rank_and_tuple.second);
4728  out_points[c] = std::get<2>(rank_and_tuple.second);
4729  out_ranks[c] = std::get<3>(rank_and_tuple.second);
4730  ++c;
4731  }
4732 
4733  return output_tuple;
4734 #endif
4735  }
4736 
4737 
4738  template <int dim, int spacedim>
4739  std::map<unsigned int, Point<spacedim>>
4741  const Mapping<dim, spacedim> & mapping)
4742  {
4743  std::map<unsigned int, Point<spacedim>> result;
4744  for (const auto &cell : container.active_cell_iterators())
4745  {
4746  if (!cell->is_artificial())
4747  {
4748  const auto vs = mapping.get_vertices(cell);
4749  for (unsigned int i = 0; i < vs.size(); ++i)
4750  result[cell->vertex_index(i)] = vs[i];
4751  }
4752  }
4753  return result;
4754  }
4755 
4756 
4757  template <int spacedim>
4758  unsigned int
4759  find_closest_vertex(const std::map<unsigned int, Point<spacedim>> &vertices,
4760  const Point<spacedim> & p)
4761  {
4762  auto id_and_v = std::min_element(
4763  vertices.begin(),
4764  vertices.end(),
4765  [&](const std::pair<const unsigned int, Point<spacedim>> &p1,
4766  const std::pair<const unsigned int, Point<spacedim>> &p2) -> bool {
4767  return p1.second.distance(p) < p2.second.distance(p);
4768  });
4769  return id_and_v->first;
4770  }
4771 
4772 
4773  template <int dim, int spacedim>
4774  std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
4775  Point<dim>>
4777  const Cache<dim, spacedim> &cache,
4778  const Point<spacedim> & p,
4780  & cell_hint,
4781  const std::vector<bool> &marked_vertices)
4782  {
4783  const auto &mesh = cache.get_triangulation();
4784  const auto &mapping = cache.get_mapping();
4785  const auto &vertex_to_cells = cache.get_vertex_to_cell_map();
4786  const auto &vertex_to_cell_centers =
4788 
4789  return find_active_cell_around_point(mapping,
4790  mesh,
4791  p,
4792  vertex_to_cells,
4793  vertex_to_cell_centers,
4794  cell_hint,
4795  marked_vertices);
4796  }
4797 
4798  template <int spacedim>
4799  std::vector<std::vector<BoundingBox<spacedim>>>
4800  exchange_local_bounding_boxes(
4801  const std::vector<BoundingBox<spacedim>> &local_bboxes,
4802  MPI_Comm mpi_communicator)
4803  {
4804 #ifndef DEAL_II_WITH_MPI
4805  (void)local_bboxes;
4806  (void)mpi_communicator;
4807  Assert(false,
4808  ExcMessage(
4809  "GridTools::exchange_local_bounding_boxes() requires MPI."));
4810  return {};
4811 #else
4812  // Step 1: preparing data to be sent
4813  unsigned int n_bboxes = local_bboxes.size();
4814  // Dimension of the array to be exchanged (number of double)
4815  int n_local_data = 2 * spacedim * n_bboxes;
4816  // data array stores each entry of each point describing the bounding boxes
4817  std::vector<double> loc_data_array(n_local_data);
4818  for (unsigned int i = 0; i < n_bboxes; ++i)
4819  for (unsigned int d = 0; d < spacedim; ++d)
4820  {
4821  // Extracting the coordinates of each boundary point
4822  loc_data_array[2 * i * spacedim + d] =
4823  local_bboxes[i].get_boundary_points().first[d];
4824  loc_data_array[2 * i * spacedim + spacedim + d] =
4825  local_bboxes[i].get_boundary_points().second[d];
4826  }
4827 
4828  // Step 2: exchanging the size of local data
4829  unsigned int n_procs = Utilities::MPI::n_mpi_processes(mpi_communicator);
4830 
4831  // Vector to store the size of loc_data_array for every process
4832  std::vector<int> size_all_data(n_procs);
4833 
4834  // Exchanging the number of bboxes
4835  int ierr = MPI_Allgather(&n_local_data,
4836  1,
4837  MPI_INT,
4838  &(size_all_data[0]),
4839  1,
4840  MPI_INT,
4841  mpi_communicator);
4842  AssertThrowMPI(ierr);
4843 
4844  // Now computing the the displacement, relative to recvbuf,
4845  // at which to store the incoming data
4846  std::vector<int> rdispls(n_procs);
4847  rdispls[0] = 0;
4848  for (unsigned int i = 1; i < n_procs; ++i)
4849  rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
4850 
4851  // Step 3: exchange the data and bounding boxes:
4852  // Allocating a vector to contain all the received data
4853  std::vector<double> data_array(rdispls.back() + size_all_data.back());
4854 
4855  ierr = MPI_Allgatherv(&(loc_data_array[0]),
4856  n_local_data,
4857  MPI_DOUBLE,
4858  &(data_array[0]),
4859  &(size_all_data[0]),
4860  &(rdispls[0]),
4861  MPI_DOUBLE,
4862  mpi_communicator);
4863  AssertThrowMPI(ierr);
4864 
4865  // Step 4: create the array of bboxes for output
4866  std::vector<std::vector<BoundingBox<spacedim>>> global_bboxes(n_procs);
4867  unsigned int begin_idx = 0;
4868  for (unsigned int i = 0; i < n_procs; ++i)
4869  {
4870  // Number of local bounding boxes
4871  unsigned int n_bbox_i = size_all_data[i] / (spacedim * 2);
4872  global_bboxes[i].resize(n_bbox_i);
4873  for (unsigned int bbox = 0; bbox < n_bbox_i; ++bbox)
4874  {
4875  Point<spacedim> p1, p2; // boundary points for bbox
4876  for (unsigned int d = 0; d < spacedim; ++d)
4877  {
4878  p1[d] = data_array[begin_idx + 2 * bbox * spacedim + d];
4879  p2[d] =
4880  data_array[begin_idx + 2 * bbox * spacedim + spacedim + d];
4881  }
4882  BoundingBox<spacedim> loc_bbox(std::make_pair(p1, p2));
4883  global_bboxes[i][bbox] = loc_bbox;
4884  }
4885  // Shifting the first index to the start of the next vector
4886  begin_idx += size_all_data[i];
4887  }
4888  return global_bboxes;
4889 #endif // DEAL_II_WITH_MPI
4890  }
4891 
4892 
4893 } /* namespace GridTools */
4894 
4895 
4896 // explicit instantiations
4897 #include "grid_tools.inst"
4898 
4899 DEAL_II_NAMESPACE_CLOSE
void remove_hanging_nodes(Triangulation< dim, spacedim > &tria, const bool isotropic=false, const unsigned int max_iterations=100)
Definition: grid_tools.cc:3608
void map_boundary_to_manifold_ids(const std::vector< types::boundary_id > &src_boundary_ids, const std::vector< types::manifold_id > &dst_manifold_ids, Triangulation< dim, spacedim > &tria, const std::vector< types::boundary_id > &reset_boundary_ids={})
Definition: grid_tools.cc:3475
std::vector< CellData< 1 > > boundary_lines
Definition: tria.h:258
Transformed quadrature weights.
void laplace_transform(const std::map< unsigned int, Point< dim >> &new_points, Triangulation< dim > &tria, const Function< dim, double > *coefficient=nullptr, const bool solve_for_absolute_positions=false)
static::ExceptionBase & ExcScalingFactorNotPositive(double arg1)
unsigned int n_raw_faces() const
Definition: tria.cc:12544
static void reorder_cells(std::vector< CellData< dim >> &original_cells, const bool use_new_style_ordering=false)
static const unsigned int invalid_unsigned_int
Definition: types.h:173
virtual std::array< Point< spacedim >, GeometryInfo< dim >::vertices_per_cell > get_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
Definition: mapping.cc:26
unsigned int manifold_id
Definition: types.h:123
std::map< unsigned int, Point< spacedim > > get_all_vertices_at_boundary(const Triangulation< dim, spacedim > &tria)
Definition: grid_tools.cc:875
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: dof_handler.cc:943
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
void copy_boundary_to_manifold_id(Triangulation< dim, spacedim > &tria, const bool reset_boundary_ids=false)
Definition: grid_tools.cc:3450
return_type guess_point_owner(const std::vector< std::vector< BoundingBox< spacedim >>> &global_bboxes, const std::vector< Point< spacedim >> &points)
Definition: grid_tools.cc:1867
void create_laplace_matrix(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Quadrature< dim > &q, SparseMatrix< double > &matrix, const Function< spacedim > *const a=nullptr, const AffineConstraints< double > &constraints=AffineConstraints< double >())
double diameter(const Triangulation< dim, spacedim > &tria)
Definition: grid_tools.cc:75
void distort_random(const double factor, Triangulation< dim, spacedim > &triangulation, const bool keep_boundary=true)
Definition: grid_tools.cc:908
const std::vector< Point< spacedim > > & get_vertices() const
types::subdomain_id locally_owned_subdomain() const override
Definition: tria_base.cc:335
cell_iterator end() const
Definition: tria.cc:12004
std::map< unsigned int, Point< spacedim > > extract_used_vertices(const Triangulation< dim, spacedim > &container, const Mapping< dim, spacedim > &mapping=StaticMappingQ1< dim, spacedim >::mapping)
Definition: grid_tools.cc:4740
MeshType< dim, spacedim >::active_cell_iterator find_active_cell_around_point(const MeshType< dim, spacedim > &mesh, const Point< spacedim > &p, const std::vector< bool > &marked_vertices=std::vector< bool >())
std::pair< unsigned int, double > get_longest_direction(typename Triangulation< dim, spacedim >::active_cell_iterator cell)
Definition: grid_tools.cc:3576
active_face_iterator begin_active_face() const
Definition: tria.cc:12117
BoundingBox< spacedim > compute_bounding_box(const Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:420
Task< RT > new_task(const std::function< RT()> &function)
unsigned int find_closest_vertex_of_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell, const Point< spacedim > &position)
Definition: grid_tools.cc:1637
bool check_consistency(const unsigned int dim) const
Definition: tria.cc:48
IteratorRange< active_cell_iterator > active_cell_iterators() const
Definition: tria.cc:12060
void regularize_corner_cells(Triangulation< dim, spacedim > &tria, const double limit_angle_fraction=.75)
Definition: grid_tools.cc:3678
void add(const size_type i, const size_type j)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:725
double volume(const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping=(StaticMappingQ1< dim, spacedim >::mapping))
Definition: grid_tools.cc:133
std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > vertex_to_cell_map(const Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:1919
size_type n() const
return_type distributed_compute_point_locations(const GridTools::Cache< dim, spacedim > &cache, const std::vector< Point< spacedim >> &local_points, const std::vector< std::vector< BoundingBox< spacedim >>> &global_bboxes)
Definition: grid_tools.cc:4506
const std::vector< bool > & get_used_vertices() const
Definition: tria.cc:13104
std::map< unsigned int, types::global_vertex_index > compute_local_to_global_vertex_index_map(const parallel::distributed::Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:1970
numbers::NumberTraits< Number >::real_type distance(const Point< dim, Number > &p) const
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1301
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
types::boundary_id boundary_id
Definition: tria.h:171
virtual Point< dim > transform_real_to_unit_cell(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p) const =0
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
cell_iterator begin(const unsigned int level=0) const
Definition: tria.cc:11915
unsigned int n_active_cells() const
Definition: tria.cc:12509
double maximal_cell_diameter(const Triangulation< dim, spacedim > &triangulation, const Mapping< dim, spacedim > &mapping=(StaticMappingQ1< dim, spacedim >::mapping))
Definition: grid_tools.cc:2916
void partition_multigrid_levels(Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2763
double minimal_cell_diameter(const Triangulation< dim, spacedim > &triangulation, const Mapping< dim, spacedim > &mapping=(StaticMappingQ1< dim, spacedim >::mapping))
Definition: grid_tools.cc:2888
void partition_triangulation_zorder(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2657
unsigned long long int global_dof_index
Definition: types.h:72
unsigned int n_levels() const
void partition_triangulation(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const SparsityTools::Partitioner partitioner=SparsityTools::Partitioner::metis)
Definition: grid_tools.cc:2454
void set_manifold(const types::manifold_id number, const Manifold< dim, spacedim > &manifold_object)
Definition: tria.cc:10268
static double distance_to_unit_cell(const Point< dim > &p)
void delete_unused_vertices(std::vector< Point< spacedim >> &vertices, std::vector< CellData< dim >> &cells, SubCellData &subcelldata)
Definition: grid_tools.cc:434
void get_vertex_connectivity_of_cells(const Triangulation< dim, spacedim > &triangulation, DynamicSparsityPattern &connectivity)
Definition: grid_tools.cc:2383
static const double PI
Definition: numbers.h:143
virtual void execute_coarsening_and_refinement()
Definition: tria.cc:13229
Definition: tria.h:81
virtual MPI_Comm get_communicator() const
Definition: tria_base.cc:155
void join() const
unsigned int size() const
static::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static::ExceptionBase & ExcMessage(std::string arg1)
unsigned int subdomain_id
Definition: types.h:43
unsigned int n_cells() const
Definition: tria.cc:12501
T sum(const T &t, const MPI_Comm &mpi_communicator)
void get_vertex_connectivity_of_cells_on_level(const Triangulation< dim, spacedim > &triangulation, const unsigned int level, DynamicSparsityPattern &connectivity)
Definition: grid_tools.cc:2418
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices, const Partitioner partitioner=Partitioner::metis)
virtual void create_triangulation(const std::vector< Point< spacedim >> &vertices, const std::vector< CellData< dim >> &cells, const SubCellData &subcelldata)
Definition: tria.cc:10556
#define Assert(cond, exc)
Definition: exceptions.h:1227
numbers::NumberTraits< Number >::real_type distance_square(const Point< dim, Number > &p) const
types::global_dof_index n_dofs() const
Signals signals
Definition: tria.h:2287
std::vector< types::manifold_id > get_manifold_ids() const
Definition: tria.cc:10450
void reinit(const size_type m, const size_type n, const IndexSet &rowset=IndexSet())
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
Abstract base class for mapping classes.
Definition: dof_tools.h:57
const std::vector< std::vector< Tensor< 1, spacedim > > > & get_vertex_to_cell_centers_directions() const
std::list< typename Triangulation< dim, spacedim >::cell_iterator > distorted_cells
Definition: tria.h:1623
size_type n_cols() const
virtual bool has_hanging_nodes() const
Definition: tria.cc:12639
std::vector< BoundingBox< MeshType::space_dimension > > compute_mesh_predicate_bounding_box(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate, const unsigned int refinement_level=0, const bool allow_merge=false, const unsigned int max_boxes=numbers::invalid_unsigned_int)
Definition: grid_tools.cc:1720
types::material_id material_id
Definition: tria.h:160
void remove_anisotropy(Triangulation< dim, spacedim > &tria, const double max_ratio=1.6180339887, const unsigned int max_iterations=5)
Definition: grid_tools.cc:3645
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
Definition: tria.cc:10394
std::vector< types::boundary_id > get_boundary_ids() const
Definition: tria.cc:10417
void initialize(const MatrixType &A, const AdditionalData &parameters=AdditionalData())
IteratorState::IteratorStates state() const
void copy_material_to_manifold_id(Triangulation< dim, spacedim > &tria, const bool compute_face_ids=false)
Definition: grid_tools.cc:3549
void rotate(const double angle, Triangulation< 2 > &triangulation)
Definition: grid_tools.cc:707
Triangulation< dim, spacedim >::DistortedCellList fix_up_distorted_child_cells(const typename Triangulation< dim, spacedim >::DistortedCellList &distorted_cells, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:3411
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
std::vector< unsigned int > invert_permutation(const std::vector< unsigned int > &permutation)
Definition: utilities.cc:503
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:96
cell_iterator end() const
Definition: dof_handler.cc:959
bool vertex_used(const unsigned int index) const
void reinit(const TriaIterator< DoFCellAccessor< DoFHandlerType< dim, spacedim >, level_dof_access >> &cell)
Definition: fe_values.cc:4638
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:69
types::manifold_id manifold_id
Definition: tria.h:182
void add_constraints(const ConstraintList &new_constraints)
numbers::NumberTraits< Number >::real_type square() const
std::vector< std::vector< Tensor< 1, spacedim > > > vertex_to_cell_centers_directions(const Triangulation< dim, spacedim > &mesh, const std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator >> &vertex_to_cells)
Definition: grid_tools.cc:1436
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
Point< Iterator::AccessorType::space_dimension > project_to_object(const Iterator &object, const Point< Iterator::AccessorType::space_dimension > &trial_point)
void swap(Vector< Number > &u, Vector< Number > &v)
Definition: vector.h:1353
void reorder_hierarchical(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices)
static void alternating_form_at_vertices(const Point< spacedim >(&vertices)[vertices_per_cell], Tensor< spacedim-dim, spacedim >(&forms)[vertices_per_cell])
const types::subdomain_id artificial_subdomain_id
Definition: types.h:272
const types::manifold_id invalid_manifold_id
Definition: types.h:234
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1443
face_iterator end_face() const
Definition: tria.cc:12138
void transform(const Transformation &transformation, Triangulation< dim, spacedim > &triangulation)
T min(const T &t, const MPI_Comm &mpi_communicator)
std::vector< typename MeshType< dim, spacedim >::active_cell_iterator > find_cells_adjacent_to_vertex(const MeshType< dim, spacedim > &container, const unsigned int vertex_index)
Definition: grid_tools.cc:1298
std::vector< CellData< 2 > > boundary_quads
Definition: tria.h:266
size_type n_rows() const
void get_subdomain_association(const Triangulation< dim, spacedim > &triangulation, std::vector< types::subdomain_id > &subdomain)
Definition: grid_tools.cc:2790
virtual void distribute_dofs(const FiniteElement< dim, spacedim > &fe)
void get_face_connectivity_of_cells(const Triangulation< dim, spacedim > &triangulation, DynamicSparsityPattern &connectivity)
Definition: grid_tools.cc:2327
Definition: fe.h:36
void refine_global(const unsigned int times=1)
Definition: tria.cc:10773
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:80
virtual bool preserves_vertex_locations() const =0
static::ExceptionBase & ExcNotImplemented()
return_type compute_point_locations(const Cache< dim, spacedim > &cache, const std::vector< Point< spacedim >> &points, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint=typename Triangulation< dim, spacedim >::active_cell_iterator())
Definition: grid_tools.cc:3999
Iterator points to a valid object.
std::vector< bool > get_locally_owned_vertices(const Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2826
const Mapping< dim, spacedim > & get_mapping() const
static::ExceptionBase & ExcVertexNotUsed(unsigned int arg1)
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: tria.cc:11935
unsigned long long int global_vertex_index
Definition: types.h:48
const Triangulation< dim, spacedim > & get_triangulation() const
void make_sparsity_pattern(const DoFHandlerType &dof_handler, SparsityPatternType &sparsity_pattern, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
unsigned int n_vertices() const
std::map< unsigned int, T > some_to_some(const MPI_Comm &comm, const std::map< unsigned int, T > &objects_to_send)
T max(const T &t, const MPI_Comm &mpi_communicator)
double JxW(const unsigned int quadrature_point) const
void apply_constraints(VectorType &v, const bool matrix_is_symmetric) const
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:698
const std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > & get_vertex_to_cell_map() const
unsigned int count_cells_with_subdomain_association(const Triangulation< dim, spacedim > &triangulation, const types::subdomain_id subdomain)
Definition: grid_tools.cc:2807
unsigned int find_closest_vertex(const std::map< unsigned int, Point< spacedim >> &vertices, const Point< spacedim > &p)
Definition: grid_tools.cc:4759
virtual void clear()
Definition: tria.cc:10232
unsigned int vertices[GeometryInfo< structdim >::vertices_per_cell]
Definition: tria.h:141
static::ExceptionBase & ExcInternalError()
Triangulation< dim, spacedim > & get_triangulation()
Definition: tria.cc:13182
void delete_duplicated_vertices(std::vector< Point< spacedim >> &all_vertices, std::vector< CellData< dim >> &cells, SubCellData &subcelldata, std::vector< unsigned int > &considered_vertices, const double tol=1e-12)
Definition: grid_tools.cc:533