Reference documentation for deal.II version 9.2.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
tria_description.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2019 - 2020 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 
17 #include <deal.II/base/mpi.h>
18 
20 
23 
25 #include <deal.II/grid/tria.h>
27 
29 
31 {
32  namespace Utilities
33  {
34  namespace
35  {
39  template <int dim, int spacedim>
40  void
41  set_user_flag_and_of_its_parents(
43  {
44  cell->set_user_flag();
45  if (cell->level() != 0)
46  set_user_flag_and_of_its_parents(cell->parent());
47  }
48 
49 
54  template <int dim>
56  convert_cell_id_binary_type_to_level_coarse_cell_id(
57  const typename CellId::binary_type &binary_representation)
58  {
59  // exploiting the structure of CellId::binary_type
60  // see also the documentation of CellId
61 
62  // actual coarse-grid id
63  const unsigned int coarse_cell_id = binary_representation[0];
64  const unsigned int n_child_indices = binary_representation[1] >> 2;
65 
66  const unsigned int children_per_value =
67  sizeof(CellId::binary_type::value_type) * 8 / dim;
68  unsigned int child_level = 0;
69  unsigned int binary_entry = 2;
70 
71  // path to the get to the cell
72  std::vector<unsigned int> cell_indices;
73  while (child_level < n_child_indices)
74  {
75  Assert(binary_entry < binary_representation.size(),
77 
78  for (unsigned int j = 0; j < children_per_value; ++j)
79  {
80  unsigned int cell_index =
81  (((binary_representation[binary_entry] >> (j * dim))) &
83  cell_indices.push_back(cell_index);
84  ++child_level;
85  if (child_level == n_child_indices)
86  break;
87  }
88  ++binary_entry;
89  }
90 
91  // compute new coarse-grid id: c_{i+1} = c_{i}*2^dim + q;
92  types::coarse_cell_id level_coarse_cell_id = coarse_cell_id;
93  for (auto i : cell_indices)
94  level_coarse_cell_id =
95  level_coarse_cell_id * GeometryInfo<dim>::max_children_per_cell + i;
96 
97  return level_coarse_cell_id;
98  }
99  } // namespace
100 
101 
102  template <int dim, int spacedim>
103  Description<dim, spacedim>
105  const ::Triangulation<dim, spacedim> &tria,
106  const MPI_Comm comm,
107  const TriangulationDescription::Settings settings,
108  const unsigned int my_rank_in)
109  {
110  if (auto tria_pdt = dynamic_cast<
112  Assert(comm == tria_pdt->get_communicator(),
113  ExcMessage("MPI communicators do not match."));
114 
115  // First, figure out for what rank we are supposed to build the
116  // TriangulationDescription::Description object
117  unsigned int my_rank = my_rank_in;
119  my_rank < ::Utilities::MPI::n_mpi_processes(comm),
120  ExcMessage("Rank has to be smaller than available processes."));
121 
122  if (auto tria_pdt = dynamic_cast<
124  {
125  Assert(
126  my_rank == numbers::invalid_unsigned_int ||
127  my_rank == ::Utilities::MPI::this_mpi_process(comm),
128  ExcMessage(
129  "If parallel::distributed::Triangulation as source triangulation, my_rank has to equal global rank."));
130 
131  my_rank = ::Utilities::MPI::this_mpi_process(comm);
132  }
133  else if (auto tria_serial =
134  dynamic_cast<const ::Triangulation<dim, spacedim> *>(
135  &tria))
136  {
137  if (my_rank == numbers::invalid_unsigned_int)
138  my_rank = ::Utilities::MPI::this_mpi_process(comm);
139  }
140  else
141  {
142  Assert(false,
143  ExcMessage("This type of triangulation is not supported!"));
144  }
145 
146  Description<dim, spacedim> construction_data;
147 
148  // store the communicator
149  construction_data.comm = comm;
150 
151 
152  std::map<unsigned int, std::vector<unsigned int>>
153  coinciding_vertex_groups;
154  std::map<unsigned int, unsigned int> vertex_to_coinciding_vertex_group;
155 
157  coinciding_vertex_groups,
158  vertex_to_coinciding_vertex_group);
159 
160  // helper function, which collects all vertices belonging to a cell
161  // (also taking into account periodicity)
162  auto add_vertices_of_cell_to_vertices_owned_by_locally_owned_cells =
163  [coinciding_vertex_groups, vertex_to_coinciding_vertex_group](
165  std::vector<bool> &vertices_owned_by_locally_owned_cells) {
166  // add local vertices
167  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
168  {
169  vertices_owned_by_locally_owned_cells[cell->vertex_index(v)] =
170  true;
171  const auto coinciding_vertex_group =
172  vertex_to_coinciding_vertex_group.find(cell->vertex_index(v));
173  if (coinciding_vertex_group !=
174  vertex_to_coinciding_vertex_group.end())
175  for (const auto &co_vertex : coinciding_vertex_groups.at(
176  coinciding_vertex_group->second))
177  vertices_owned_by_locally_owned_cells[co_vertex] = true;
178  }
179  };
180 
181  construction_data.smoothing = tria.get_mesh_smoothing();
182  construction_data.settings = settings;
183 
184  Assert(
185  !(settings &
187  (tria.get_mesh_smoothing() &
189  ExcMessage(
190  "Source triangulation has to be setup with limit_level_difference_at_vertices if the construction of the multigrid hierarchy is requested!"));
191 
192  // 1) collect locally relevant cells (set user_flag)
193  std::vector<bool> old_user_flags;
194  tria.save_user_flags(old_user_flags);
195 
196  // 1a) clear user_flags
197  const_cast<::Triangulation<dim, spacedim> &>(tria)
198  .clear_user_flags();
199 
200  // 1b) loop over levels (from fine to coarse) and mark on each level
201  // the locally relevant cells
202  for (int level = tria.get_triangulation().n_global_levels() - 1;
203  level >= 0;
204  --level)
205  {
206  // collect vertices connected to a (on any level) locally owned
207  // cell
208  std::vector<bool> vertices_owned_by_locally_owned_cells_on_level(
209  tria.n_vertices());
210  for (auto cell : tria.cell_iterators_on_level(level))
211  if (cell->level_subdomain_id() == my_rank ||
212  (cell->active() && cell->subdomain_id() == my_rank))
213  add_vertices_of_cell_to_vertices_owned_by_locally_owned_cells(
214  cell, vertices_owned_by_locally_owned_cells_on_level);
215 
216  for (auto cell : tria.active_cell_iterators())
217  if (cell->subdomain_id() == my_rank)
218  add_vertices_of_cell_to_vertices_owned_by_locally_owned_cells(
219  cell, vertices_owned_by_locally_owned_cells_on_level);
220 
221  // helper function to determine if cell is locally relevant
222  // (i.e. a cell which is connected to a vertex via a locally
223  // owned cell)
224  auto is_locally_relevant_on_level =
226  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
227  if (vertices_owned_by_locally_owned_cells_on_level
228  [cell->vertex_index(v)])
229  return true;
230  return false;
231  };
232 
233  // mark all locally relevant cells
234  for (auto cell : tria.cell_iterators_on_level(level))
235  if (is_locally_relevant_on_level(cell))
236  set_user_flag_and_of_its_parents(cell);
237  }
238 
239  // 2) set_up coarse-grid triangulation
240  {
241  std::map<unsigned int, unsigned int> vertices_locally_relevant;
242 
243  // a) loop over all cells
244  for (auto cell : tria.cell_iterators_on_level(0))
245  {
246  if (!cell->user_flag_set())
247  continue;
248 
249  // extract cell definition (with old numbering of vertices)
250  ::CellData<dim> cell_data;
251  cell_data.material_id = cell->material_id();
252  cell_data.manifold_id = cell->manifold_id();
253  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
254  cell_data.vertices[v] = cell->vertex_index(v);
255  construction_data.coarse_cells.push_back(cell_data);
256 
257  // save indices of each vertex of this cell
258  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
259  vertices_locally_relevant[cell->vertex_index(v)] =
261 
262  // save translation for corase grid: lid -> gid
263  construction_data.coarse_cell_index_to_coarse_cell_id.push_back(
264  cell->id().get_coarse_cell_id());
265  }
266 
267  // b) enumerate locally relevant vertices
268  unsigned int vertex_counter = 0;
269  for (auto &vertex : vertices_locally_relevant)
270  {
271  construction_data.coarse_cell_vertices.push_back(
272  tria.get_vertices()[vertex.first]);
273  vertex.second = vertex_counter++;
274  }
275 
276  // c) correct vertices of cells (make them local)
277  for (auto &cell : construction_data.coarse_cells)
278  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
279  cell.vertices[v] = vertices_locally_relevant[cell.vertices[v]];
280  }
281 
282 
283  // 3) collect info of each cell
284  construction_data.cell_infos.resize(
285  tria.get_triangulation().n_global_levels());
286 
287  // collect local vertices on active level
288  std::vector<bool> vertices_owned_by_locally_owned_active_cells(
289  tria.n_vertices());
290  for (auto cell : tria.active_cell_iterators())
291  if (cell->subdomain_id() == my_rank)
292  add_vertices_of_cell_to_vertices_owned_by_locally_owned_cells(
293  cell, vertices_owned_by_locally_owned_active_cells);
294 
295  // helper function to determine if cell is locally relevant
296  // on active level
297  auto is_locally_relevant_on_active_level =
299  if (cell->active())
300  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
301  if (vertices_owned_by_locally_owned_active_cells
302  [cell->vertex_index(v)])
303  return true;
304  return false;
305  };
306 
307  for (unsigned int level = 0;
308  level < tria.get_triangulation().n_global_levels();
309  ++level)
310  {
311  // collect local vertices on level
312  std::vector<bool> vertices_owned_by_locally_owned_cells_on_level(
313  tria.n_vertices());
314  for (auto cell : tria.cell_iterators_on_level(level))
315  if (cell->level_subdomain_id() == my_rank ||
316  (cell->active() && cell->subdomain_id() == my_rank))
317  add_vertices_of_cell_to_vertices_owned_by_locally_owned_cells(
318  cell, vertices_owned_by_locally_owned_cells_on_level);
319 
320  // helper function to determine if cell is locally relevant
321  // on level
322  auto is_locally_relevant_on_level =
324  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
325  if (vertices_owned_by_locally_owned_cells_on_level
326  [cell->vertex_index(v)])
327  return true;
328  return false;
329  };
330 
331  auto &level_cell_infos = construction_data.cell_infos[level];
332  for (auto cell : tria.cell_iterators_on_level(level))
333  {
334  // check if cell is locally relevant
335  if (!(cell->user_flag_set()))
336  continue;
337 
338  CellData<dim> cell_info;
339 
340  // save coarse-cell id
341  cell_info.id = cell->id().template to_binary<dim>();
342 
343  // save boundary_ids of each face of this cell
344  for (const unsigned int f : GeometryInfo<dim>::face_indices())
345  {
346  types::boundary_id boundary_ind =
347  cell->face(f)->boundary_id();
348  if (boundary_ind != numbers::internal_face_boundary_id)
349  cell_info.boundary_ids.emplace_back(f, boundary_ind);
350  }
351 
352  // save manifold id
353  {
354  // ... of cell
355  cell_info.manifold_id = cell->manifold_id();
356 
357  // ... of lines
358  if (dim >= 2)
359  for (unsigned int line = 0;
360  line < GeometryInfo<dim>::lines_per_cell;
361  ++line)
362  cell_info.manifold_line_ids[line] =
363  cell->line(line)->manifold_id();
364 
365  // ... of quads
366  if (dim == 3)
367  for (unsigned int quad = 0;
368  quad < GeometryInfo<dim>::quads_per_cell;
369  ++quad)
370  cell_info.manifold_quad_ids[quad] =
371  cell->quad(quad)->manifold_id();
372  }
373 
374  // subdomain and level subdomain id
377 
378  if (is_locally_relevant_on_active_level(cell))
379  {
380  cell_info.level_subdomain_id = cell->level_subdomain_id();
381  cell_info.subdomain_id = cell->subdomain_id();
382  }
383  else if (is_locally_relevant_on_level(cell))
384  {
385  cell_info.level_subdomain_id = cell->level_subdomain_id();
386  }
387  // else: cell is locally relevant but an artificial cell
388 
389  level_cell_infos.emplace_back(cell_info);
390  }
391  }
392 
393  const_cast<::Triangulation<dim, spacedim> &>(tria).load_user_flags(
394  old_user_flags);
395 
396  return construction_data;
397  }
398 
399 
400 
401  template <int dim, int spacedim>
404  const std::function<void(::Triangulation<dim, spacedim> &)>
405  & serial_grid_generator,
406  const std::function<void(::Triangulation<dim, spacedim> &,
407  const MPI_Comm,
408  const unsigned int)> &serial_grid_partitioner,
409  const MPI_Comm comm,
410  const int group_size,
411  const typename Triangulation<dim, spacedim>::MeshSmoothing smoothing,
412  const TriangulationDescription::Settings settings)
413  {
414 #ifndef DEAL_II_WITH_MPI
415  (void)serial_grid_generator;
416  (void)serial_grid_partitioner;
417  (void)comm;
418  (void)group_size;
419  (void)smoothing;
420  (void)settings;
421 
423 #else
424  const unsigned int my_rank =
426  const unsigned int group_root = (my_rank / group_size) * group_size;
427 
428  const int mpi_tag =
430 
431  // check if process is root of the group
432  if (my_rank == group_root)
433  {
434  // Step 1: create serial triangulation
438  static_cast<
439  typename ::Triangulation<dim, spacedim>::MeshSmoothing>(
440  smoothing |
441  Triangulation<dim,
442  spacedim>::limit_level_difference_at_vertices) :
443  smoothing);
444  serial_grid_generator(tria);
445 
446  // Step 2: partition active cells and ...
447  serial_grid_partitioner(tria, comm, group_size);
448 
449  // ... cells on the levels if multigrid is required
450  if (settings &
453 
454  const unsigned int end_group =
455  std::min(group_root + group_size,
457 
458  // 3) create Description for the other processes in group; since
459  // we expect that this function is called for huge meshes, one
460  // Description is created at a time and send away; only once the
461  // Description has been sent away, the next rank is processed.
462  for (unsigned int other_rank = group_root + 1; other_rank < end_group;
463  ++other_rank)
464  {
465  // 3a) create construction data for other ranks
466  const auto construction_data =
468  comm,
469  settings,
470  other_rank);
471  // 3b) pack
472  std::vector<char> buffer;
473  ::Utilities::pack(construction_data, buffer, false);
474 
475  // 3c) send TriangulationDescription::Description
476  const auto ierr = MPI_Send(buffer.data(),
477  buffer.size(),
478  MPI_CHAR,
479  other_rank,
480  mpi_tag,
481  comm);
482  AssertThrowMPI(ierr);
483  }
484 
485  // 4) create TriangulationDescription::Description for this process
486  // (root of group)
488  comm,
489  settings,
490  my_rank);
491  }
492  else
493  {
494  // 3a) recv packed TriangulationDescription::Description from
495  // group-root process
496  // (counter-part of 3c of root process)
497  MPI_Status status;
498  auto ierr = MPI_Probe(group_root, mpi_tag, comm, &status);
499  AssertThrowMPI(ierr);
500 
501  int len;
502  MPI_Get_count(&status, MPI_CHAR, &len);
503 
504  std::vector<char> buf(len);
505  ierr = MPI_Recv(buf.data(),
506  len,
507  MPI_CHAR,
508  status.MPI_SOURCE,
509  mpi_tag,
510  comm,
511  &status);
512  AssertThrowMPI(ierr);
513 
514  // 3b) unpack TriangulationDescription::Description (counter-part of
515  // 3b of root process)
516  auto construction_data =
517  ::Utilities::template unpack<Description<dim, spacedim>>(
518  buf, false);
519 
520  // WARNING: serialization cannot handle the MPI communicator
521  // which is the reason why we have to set it here explicitly
522  construction_data.comm = comm;
523 
524  return construction_data;
525  }
526 #endif
527  }
528 
529  } // namespace Utilities
530 } // namespace TriangulationDescription
531 
532 
533 
534 /*-------------- Explicit Instantiations -------------------------------*/
535 #include "tria_description.inst"
536 
537 
GridTools::collect_coinciding_vertices
void collect_coinciding_vertices(const Triangulation< dim, spacedim > &tria, std::map< unsigned int, std::vector< unsigned int >> &coinciding_vertex_groups, std::map< unsigned int, unsigned int > &vertex_to_coinciding_vertex_group)
Definition: grid_tools.cc:5395
TriangulationDescription::Description::cell_infos
std::vector< std::vector< CellData< dim > > > cell_infos
Definition: tria_description.h:384
TriangulationDescription::Description::comm
MPI_Comm comm
Definition: tria_description.h:396
tria_description.h
CellAccessor
Definition: tria_accessor.h:2667
Triangulation
Definition: tria.h:1109
tria.h
GeometryInfo
Definition: geometry_info.h:1224
MPI_Comm
Utilities::pack
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
Definition: utilities.h:1209
TriangulationDescription::Description::coarse_cell_index_to_coarse_cell_id
std::vector< types::coarse_cell_id > coarse_cell_index_to_coarse_cell_id
Definition: tria_description.h:377
level
unsigned int level
Definition: grid_out.cc:4355
StandardExceptions::ExcMessage
static ::ExceptionBase & ExcMessage(std::string arg1)
geometry_info.h
mpi.h
TriangulationDescription::Description::coarse_cell_vertices
std::vector< Point< spacedim > > coarse_cell_vertices
Definition: tria_description.h:370
grid_tools.h
TriangulationDescription::Utilities::create_description_from_triangulation
Description< dim, spacedim > create_description_from_triangulation(const ::Triangulation< dim, spacedim > &tria, const MPI_Comm comm, const TriangulationDescription::Settings settings=TriangulationDescription::Settings::default_setting, const unsigned int my_rank_in=numbers::invalid_unsigned_int)
Definition: tria_description.cc:104
DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:358
TriangulationDescription::CellData::manifold_id
types::manifold_id manifold_id
Definition: tria_description.h:315
GridTools::partition_multigrid_levels
void partition_multigrid_levels(Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2921
TriangulationDescription::CellData::level_subdomain_id
types::subdomain_id level_subdomain_id
Definition: tria_description.h:310
parallel::distributed::Triangulation
Definition: tria.h:242
TriangulationDescription::CellData
Definition: tria_description.h:282
TriangulationDescription::Description::smoothing
Triangulation< dim, spacedim >::MeshSmoothing smoothing
Definition: tria_description.h:406
AssertThrowMPI
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1707
TriangulationDescription
Definition: tria_description.h:245
numbers::internal_face_boundary_id
const types::boundary_id internal_face_boundary_id
Definition: types.h:250
TriangulationDescription::CellData::subdomain_id
types::subdomain_id subdomain_id
Definition: tria_description.h:305
unsigned int
StandardExceptions::ExcInternalError
static ::ExceptionBase & ExcInternalError()
tria.h
TriangulationDescription::CellData::boundary_ids
std::vector< std::pair< unsigned int, types::boundary_id > > boundary_ids
Definition: tria_description.h:338
types::coarse_cell_id
global_cell_index coarse_cell_id
Definition: types.h:114
Assert
#define Assert(cond, exc)
Definition: exceptions.h:1419
Utilities::MPI::this_mpi_process
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:128
TriangulationDescription::Description::settings
Settings settings
Definition: tria_description.h:401
Triangulation::MeshSmoothing
MeshSmoothing
Definition: tria.h:1124
dof_handler.h
dof_accessor.h
Utilities::MPI::n_mpi_processes
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:117
numbers::invalid_unsigned_int
static const unsigned int invalid_unsigned_int
Definition: types.h:191
Utilities::MPI::min
T min(const T &t, const MPI_Comm &mpi_communicator)
CellId::binary_type
std::array< unsigned int, 4 > binary_type
Definition: cell_id.h:79
Utilities::MPI::internal::Tags::fully_distributed_create
@ fully_distributed_create
TriangulationDescription::Utilities::create_description_from_triangulation()
Definition: mpi_tags.h:99
numbers::artificial_subdomain_id
const types::subdomain_id artificial_subdomain_id
Definition: types.h:302
TriangulationDescription::Utilities::create_description_from_triangulation_in_groups
Description< dim, spacedim > create_description_from_triangulation_in_groups(const std::function< void(::Triangulation< dim, spacedim > &)> &serial_grid_generator, const std::function< void(::Triangulation< dim, spacedim > &, const MPI_Comm, const unsigned int)> &serial_grid_partitioner, const MPI_Comm comm, const int group_size=1, const typename Triangulation< dim, spacedim >::MeshSmoothing smoothing=::Triangulation< dim, spacedim >::none, const TriangulationDescription::Settings setting=TriangulationDescription::Settings::default_setting)
Definition: tria_description.cc:403
TriangulationDescription::Description
Definition: tria_description.h:347
TriangulationDescription::Settings
Settings
Definition: tria_description.h:253
DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:359
TriangulationDescription::CellData::manifold_quad_ids
std::array< types::manifold_id, dim==1 ? 1 :GeometryInfo< 3 >::quads_per_cell > manifold_quad_ids
Definition: tria_description.h:332
TriangulationDescription::CellData::id
CellId::binary_type id
Definition: tria_description.h:300
TriaIterator
Definition: tria_iterator.h:578
TriangulationDescription::Description::coarse_cells
std::vector<::CellData< dim > > coarse_cells
Definition: tria_description.h:365
Utilities
Definition: cuda.h:31
TriangulationDescription::construct_multigrid_hierarchy
@ construct_multigrid_hierarchy
Definition: tria_description.h:264
TriangulationDescription::CellData::manifold_line_ids
std::array< types::manifold_id, GeometryInfo< dim >::lines_per_cell > manifold_line_ids
Definition: tria_description.h:323