deal.II version GIT relicensing-6846-gd1ccc50c04 2026-10-05 21:50:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
shared_tria.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2015 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/mpi.h>
14#include <deal.II/base/mpi.templates.h>
16
19
22#include <deal.II/grid/tria.h>
25
27
28#include <type_traits>
29
30
32
33#ifdef DEAL_II_WITH_MPI
34namespace parallel
35{
36 namespace shared
37 {
38 template <int dim, int spacedim>
41 const MPI_Comm mpi_communicator,
42 const typename ::Triangulation<dim, spacedim>::MeshSmoothing
43 smooth_grid,
44 const bool allow_artificial_cells,
45 const Settings settings)
46 : ::parallel::TriangulationBase<dim, spacedim>(mpi_communicator,
47 smooth_grid,
48 false)
49 , settings(settings)
50 , allow_artificial_cells(allow_artificial_cells)
51 {
52 const auto partition_settings =
53 (partition_zoltan | partition_metis | partition_zorder |
54 partition_custom_signal) &
55 settings;
56 Assert(partition_settings == partition_auto ||
57 partition_settings == partition_metis ||
58 partition_settings == partition_zoltan ||
59 partition_settings == partition_zorder ||
60 partition_settings == partition_custom_signal,
61 ExcMessage("Settings must contain exactly one type of the active "
62 "cell partitioning scheme."));
63
64 if (settings & construct_multigrid_hierarchy)
65 Assert(allow_artificial_cells,
66 ExcMessage("construct_multigrid_hierarchy requires "
67 "allow_artificial_cells to be set to true."));
68 }
69
70
71
72 template <int dim, int spacedim>
74 bool Triangulation<dim, spacedim>::is_multilevel_hierarchy_constructed()
75 const
76 {
77 return (settings & construct_multigrid_hierarchy);
78 }
79
80
81
82 template <int dim, int spacedim>
84 void Triangulation<dim, spacedim>::partition()
85 {
86 if constexpr (running_in_debug_mode())
87 {
88 // Check that all meshes are the same (or at least have the same
89 // total number of active cells):
90 const unsigned int max_active_cells =
91 Utilities::MPI::max(this->n_active_cells(),
92 this->get_mpi_communicator());
93 Assert(
94 max_active_cells == this->n_active_cells(),
96 "A parallel::shared::Triangulation needs to be refined in the same "
97 "way on all processors, but the participating processors don't "
98 "agree on the number of active cells."));
99 }
100
101 auto partition_settings = (partition_zoltan | partition_metis |
102 partition_zorder | partition_custom_signal) &
103 settings;
104 if (partition_settings == partition_auto)
105# ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
106 partition_settings = partition_zoltan;
107# elif defined DEAL_II_WITH_METIS
108 partition_settings = partition_metis;
109# else
110 partition_settings = partition_zorder;
111# endif
112
113 if (partition_settings == partition_zoltan)
114 {
115# ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
116 AssertThrow(false,
118 "Choosing 'partition_zoltan' requires the library "
119 "to be compiled with support for Zoltan! "
120 "Instead, you might use 'partition_auto' to select "
121 "a partitioning algorithm that is supported "
122 "by your current configuration."));
123# else
125 this->n_subdomains, *this, SparsityTools::Partitioner::zoltan);
126# endif
127 }
128 else if (partition_settings == partition_metis)
129 {
130# ifndef DEAL_II_WITH_METIS
131 AssertThrow(false,
133 "Choosing 'partition_metis' requires the library "
134 "to be compiled with support for METIS! "
135 "Instead, you might use 'partition_auto' to select "
136 "a partitioning algorithm that is supported "
137 "by your current configuration."));
138# else
139 GridTools::partition_triangulation(this->n_subdomains,
140 *this,
142# endif
143 }
144 else if (partition_settings == partition_zorder)
145 {
146 GridTools::partition_triangulation_zorder(this->n_subdomains, *this);
147 }
148 else if (partition_settings == partition_custom_signal)
149 {
150 // User partitions mesh manually
151 }
152 else
153 {
155 }
156
157 // do not partition multigrid levels if user is
158 // defining a custom partition
159 if ((settings & construct_multigrid_hierarchy) &&
160 !(settings & partition_custom_signal))
162
163 true_subdomain_ids_of_cells.resize(this->n_active_cells());
164
165 // loop over all cells and mark artificial:
167 spacedim>::active_cell_iterator
168 cell = this->begin_active(),
169 endc = this->end();
170
171 if (allow_artificial_cells)
172 {
173 // get active halo layer of (ghost) cells
174 // parallel::shared::Triangulation<dim>::
175 std::function<bool(
178 predicate = IteratorFilters::SubdomainEqualTo(this->my_subdomain);
179
180 const std::vector<typename parallel::shared::Triangulation<
181 dim,
182 spacedim>::active_cell_iterator>
183 active_halo_layer_vector =
185 predicate);
186 std::set<typename parallel::shared::Triangulation<dim, spacedim>::
187 active_cell_iterator>
188 active_halo_layer(active_halo_layer_vector.begin(),
189 active_halo_layer_vector.end());
190
191 for (unsigned int index = 0; cell != endc; cell++, index++)
192 {
193 // store original/true subdomain ids:
194 true_subdomain_ids_of_cells[index] = cell->subdomain_id();
195
196 if (cell->is_locally_owned() == false &&
197 active_halo_layer.find(cell) == active_halo_layer.end())
198 cell->set_subdomain_id(numbers::artificial_subdomain_id);
199 }
200
201 // loop over all cells in multigrid hierarchy and mark artificial:
202 if (settings & construct_multigrid_hierarchy)
203 {
204 true_level_subdomain_ids_of_cells.resize(this->n_levels());
205
206 std::function<bool(
208 cell_iterator &)>
210 for (unsigned int lvl = 0; lvl < this->n_levels(); ++lvl)
211 {
212 true_level_subdomain_ids_of_cells[lvl].resize(
213 this->n_cells(lvl));
214
215 const std::vector<typename parallel::shared::Triangulation<
216 dim,
217 spacedim>::cell_iterator>
218 level_halo_layer_vector =
220 *this, predicate, lvl);
221 std::set<typename parallel::shared::
222 Triangulation<dim, spacedim>::cell_iterator>
223 level_halo_layer(level_halo_layer_vector.begin(),
224 level_halo_layer_vector.end());
225
227 cell_iterator cell = this->begin(lvl),
228 endc = this->end(lvl);
229 for (unsigned int index = 0; cell != endc; cell++, index++)
230 {
231 // Store true level subdomain IDs before setting
232 // artificial
233 true_level_subdomain_ids_of_cells[lvl][index] =
234 cell->level_subdomain_id();
235
236 // for active cells, we must have knowledge of level
237 // subdomain ids of all neighbors to our subdomain, not
238 // just neighbors on the same level. if the cells
239 // subdomain id was not set to artitficial above, we will
240 // also keep its level subdomain id since it is either
241 // owned by this processor or in the ghost layer of the
242 // active mesh.
243 if (cell->is_active() &&
244 cell->subdomain_id() !=
246 continue;
247
248 // we must have knowledge of our parent in the hierarchy
249 if (cell->has_children())
250 {
251 bool keep_cell = false;
252 for (unsigned int c = 0; c < cell->n_children(); ++c)
253 if (cell->child(c)->level_subdomain_id() ==
254 this->my_subdomain)
255 {
256 keep_cell = true;
257 break;
258 }
259 if (keep_cell)
260 continue;
261 }
262
263 // we must have knowledge of our neighbors on the same
264 // level
265 if (!cell->is_locally_owned_on_level() &&
266 level_halo_layer.find(cell) != level_halo_layer.end())
267 continue;
268
269 // mark all other cells to artificial
270 cell->set_level_subdomain_id(
272 }
273 }
274 }
275 }
276 else
277 {
278 // just store true subdomain ids
279 for (unsigned int index = 0; cell != endc; cell++, index++)
280 true_subdomain_ids_of_cells[index] = cell->subdomain_id();
281 }
282
283 if constexpr (running_in_debug_mode())
284 {
285 {
286 // Assert that each cell is owned by a processor
287 const unsigned int n_my_cells = std::count_if(
288 this->begin_active(),
290 this->end()),
291 [](const auto &i) { return (i.is_locally_owned()); });
292
293 const unsigned int total_cells =
294 Utilities::MPI::sum(n_my_cells, this->get_mpi_communicator());
295 Assert(total_cells == this->n_active_cells(),
296 ExcMessage("Not all cells are assigned to a processor."));
297 }
298
299 // If running with multigrid, assert that each level
300 // cell is owned by a processor
301 if (settings & construct_multigrid_hierarchy)
302 {
303 const unsigned int n_my_cells =
304 std::count_if(this->begin(), this->end(), [](const auto &i) {
305 return (i.is_locally_owned_on_level());
306 });
307
308
309 const unsigned int total_cells =
310 Utilities::MPI::sum(n_my_cells, this->get_mpi_communicator());
311 Assert(total_cells == this->n_cells(),
312 ExcMessage("Not all cells are assigned to a processor."));
313 }
314 }
315 }
316
317
318
319 template <int dim, int spacedim>
321 bool Triangulation<dim, spacedim>::with_artificial_cells() const
322 {
323 return allow_artificial_cells;
324 }
325
326
327
328 template <int dim, int spacedim>
330 const std::vector<types::subdomain_id>
332 {
333 return true_subdomain_ids_of_cells;
334 }
335
336
337
338 template <int dim, int spacedim>
340 const std::vector<types::subdomain_id>
342 const unsigned int level) const
343 {
344 Assert(level < true_level_subdomain_ids_of_cells.size(),
346 Assert(true_level_subdomain_ids_of_cells[level].size() ==
347 this->n_cells(level),
349 return true_level_subdomain_ids_of_cells[level];
350 }
351
352
353
354 template <int dim, int spacedim>
356 void Triangulation<dim,
357 spacedim>::communicate_coarsening_and_refinement_flags()
358 {
359 // make sure that all refinement/coarsening flags are the same on all
360 // processes
361 {
362 // Obtain the type used to store the different possibilities
363 // a cell can be refined. This is a bit awkward because
364 // what `cell->refine_flag_set()` returns is a struct
365 // type, RefinementCase, which internally stores a
366 // std::uint8_t, which actually holds integers of
367 // enum type RefinementPossibilities<dim>::Possibilities.
368 // In the following, use the actual name of the enum, but
369 // make sure that it is in fact a `std::uint8_t` or
370 // equally sized type.
371 using int_type = std::underlying_type_t<
373 static_assert(sizeof(int_type) == sizeof(std::uint8_t),
374 "Internal type mismatch.");
375
376 std::vector<int_type> refinement_configurations(this->n_active_cells() *
377 2,
378 int_type(0));
379 for (const auto &cell : this->active_cell_iterators())
380 if (cell->is_locally_owned())
381 {
382 refinement_configurations[cell->active_cell_index() * 2 + 0] =
383 static_cast<int_type>(cell->refine_flag_set());
384 refinement_configurations[cell->active_cell_index() * 2 + 1] =
385 static_cast<int_type>(cell->coarsen_flag_set() ? 1 : 0);
386 }
387
388 Utilities::MPI::max(refinement_configurations,
389 this->get_mpi_communicator(),
390 refinement_configurations);
391
392 for (const auto &cell : this->active_cell_iterators())
393 {
394 cell->clear_refine_flag();
395 cell->clear_coarsen_flag();
396
397 Assert(
398 (refinement_configurations[cell->active_cell_index() * 2 + 0] >
399 0 ?
400 1 :
401 0) +
402 refinement_configurations[cell->active_cell_index() * 2 +
403 1] <=
404 1,
406 "Refinement/coarsening flags of cells are not consistent in parallel!"));
407
408 if (refinement_configurations[cell->active_cell_index() * 2 + 0] !=
409 0)
410 cell->set_refine_flag(RefinementCase<dim>(
411 refinement_configurations[cell->active_cell_index() * 2 + 0]));
412
413 if (refinement_configurations[cell->active_cell_index() * 2 + 1] >
414 0)
415 cell->set_coarsen_flag();
416 }
417 }
418 }
419
420
421
422 template <int dim, int spacedim>
424 bool Triangulation<dim, spacedim>::prepare_coarsening_and_refinement()
425 {
426 communicate_coarsening_and_refinement_flags();
427
428 return ::Triangulation<dim, spacedim>::
429 prepare_coarsening_and_refinement();
430 }
431
432
433
434 template <int dim, int spacedim>
436 void Triangulation<dim, spacedim>::execute_coarsening_and_refinement()
437 {
438 communicate_coarsening_and_refinement_flags();
439
441 partition();
442 this->update_number_cache();
443 }
444
445
446
447 template <int dim, int spacedim>
449 void Triangulation<dim, spacedim>::create_triangulation(
450 const std::vector<Point<spacedim>> &vertices,
451 const std::vector<CellData<dim>> &cells,
452 const SubCellData &subcelldata)
453 {
454 try
455 {
457 vertices, cells, subcelldata);
458 }
459 catch (
460 const typename ::Triangulation<dim, spacedim>::DistortedCellList
461 &)
462 {
463 // the underlying triangulation should not be checking for distorted
464 // cells
466 }
467 partition();
468 this->update_number_cache();
469 }
470
471
472
473 template <int dim, int spacedim>
475 void Triangulation<dim, spacedim>::create_triangulation(
476 const TriangulationDescription::Description<dim, spacedim>
477 &construction_data)
478 {
479 (void)construction_data;
480
482 }
483
484
485
486 template <int dim, int spacedim>
488 void Triangulation<dim, spacedim>::copy_triangulation(
489 const ::Triangulation<dim, spacedim> &other_tria)
490 {
491 Assert(
492 (dynamic_cast<
493 const ::parallel::DistributedTriangulationBase<dim, spacedim>
494 *>(&other_tria) == nullptr),
496 "Cannot use this function on parallel::distributed::Triangulation."));
497
499 other_tria);
500 partition();
501 this->update_number_cache();
502 }
503 } // namespace shared
504} // namespace parallel
505
506#else
507
508namespace parallel
509{
510 namespace shared
511 {
512 template <int dim, int spacedim>
515 {
517 return true;
518 }
519
520
521
522 template <int dim, int spacedim>
525 const
526 {
527 return false;
528 }
529
530
531
532 template <int dim, int spacedim>
534 const std::vector<unsigned int>
536 {
538 return true_subdomain_ids_of_cells;
539 }
540
541
542
543 template <int dim, int spacedim>
545 const std::vector<unsigned int>
547 const unsigned int) const
548 {
550 return true_level_subdomain_ids_of_cells;
551 }
552 } // namespace shared
553} // namespace parallel
554
555
556#endif
557
558
559
560namespace internal
561{
562 namespace parallel
563 {
564 namespace shared
565 {
566 template <int dim, int spacedim>
569 : shared_tria(
570 dynamic_cast<
571 const ::parallel::shared::Triangulation<dim, spacedim> *>(
572 &tria))
573 {
574 if (shared_tria && shared_tria->with_artificial_cells())
575 {
576 // Save the current set of subdomain IDs, and set subdomain IDs
577 // to the "true" owner of each cell.
578 const std::vector<types::subdomain_id> &true_subdomain_ids =
579 shared_tria->get_true_subdomain_ids_of_cells();
580
581 saved_subdomain_ids.resize(shared_tria->n_active_cells());
582 for (const auto &cell : shared_tria->active_cell_iterators())
583 {
584 const unsigned int index = cell->active_cell_index();
585 saved_subdomain_ids[index] = cell->subdomain_id();
586 cell->set_subdomain_id(true_subdomain_ids[index]);
587 }
588 }
589 }
590
591
592
593 template <int dim, int spacedim>
596 {
597 if (shared_tria && shared_tria->with_artificial_cells())
598 {
599 // Undo the subdomain modification.
600 for (const auto &cell : shared_tria->active_cell_iterators())
601 {
602 const unsigned int index = cell->active_cell_index();
603 cell->set_subdomain_id(saved_subdomain_ids[index]);
604 }
605 }
606 }
607 } // namespace shared
608 } // namespace parallel
609} // namespace internal
610
611
612/*-------------- Explicit Instantiations -------------------------------*/
613#include "distributed/shared_tria.inst"
614
*  iterator end()
*  *  iterator begin()
Definition point.h:111
cell_iterator end() const
const ObserverPointer< const ::parallel::shared::Triangulation< dim, spacedim > > shared_tria
TemporarilyRestoreSubdomainIds(const Triangulation< dim, spacedim > &tria)
types::subdomain_id my_subdomain
Definition tria_base.h:344
virtual void copy_triangulation(const ::Triangulation< dim, spacedim > &old_tria) override
Definition tria_base.cc:65
virtual void execute_coarsening_and_refinement() override
typename ::Triangulation< dim, spacedim >::active_cell_iterator active_cell_iterator
const std::vector< types::subdomain_id > & get_true_subdomain_ids_of_cells() const
typename ::Triangulation< dim, spacedim >::cell_iterator cell_iterator
const std::vector< types::subdomain_id > & get_true_level_subdomain_ids_of_cells(const unsigned int level) const
virtual bool is_multilevel_hierarchy_constructed() const override
virtual void create_triangulation(const std::vector< Point< spacedim > > &vertices, const std::vector< CellData< dim > > &cells, const SubCellData &subcelldata) override
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:249
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int level
Definition grid_out.cc:4642
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::size_t size
Definition mpi.cc:733
void partition_triangulation_zorder(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const bool group_siblings=true)
std::vector< typename MeshType::active_cell_iterator > compute_active_cell_halo_layer(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate)
void partition_multigrid_levels(Triangulation< dim, spacedim > &triangulation)
std::vector< typename MeshType::cell_iterator > compute_cell_halo_layer_on_level(const MeshType &mesh, const std::function< bool(const typename MeshType::cell_iterator &)> &predicate, const unsigned int level)
void partition_triangulation(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const SparsityTools::Partitioner partitioner=SparsityTools::Partitioner::metis)
T sum(const T &t, const MPI_Comm mpi_communicator)
T max(const T &t, const MPI_Comm mpi_communicator)
constexpr types::subdomain_id artificial_subdomain_id
Definition types.h:406
STL namespace.