72 unsigned int n_pieces)
84 libmesh_assert_greater (n_pieces, 0);
87 if (!
mesh.is_serial())
89 libMesh::out <<
"WARNING: Forced to gather a distributed mesh for METIS" << std::endl;
94#ifndef LIBMESH_HAVE_METIS
97 libMesh::out <<
"ERROR: The library has been built without" << std::endl
98 <<
"Metis support. Using a space-filling curve" << std::endl
99 <<
"partitioner instead!" << std::endl;);
107 LOG_SCOPE(
"partition_range()",
"MetisPartitioner");
109 const dof_id_type n_range_elem = cast_int<dof_id_type>(std::distance(beg, end));
118 global_index_map.reserve (n_range_elem);
121 std::vector<dof_id_type> global_index;
125 beg, end, global_index);
127 libmesh_assert_equal_to (global_index.size(), n_range_elem);
131#ifdef LIBMESH_ENABLE_UNIQUE_ID
133 for (
const auto & elem :
as_range(beg, end))
134 global_index_map.
emplace(elem->id(), global_index[cnt++]);
141 std::unordered_map<dof_id_type, std::vector<dof_id_type>>
142 global_index_inverses;
143 bool found_duplicate_indices =
false;
146 for (
const auto & elem :
as_range(beg, end))
148 auto & vec = global_index_inverses[global_index[cnt++]];
150 found_duplicate_indices =
true;
151 vec.push_back(elem->id());
158 if (found_duplicate_indices)
160 const std::map<dof_id_type, std::vector<dof_id_type>>
161 sorted_inverses(global_index_inverses.begin(),
162 global_index_inverses.end());
163 std::size_t new_global_index=0;
164 for (
const auto & [index, elem_ids] : sorted_inverses)
166 global_index_map.
emplace(elem_id, new_global_index++);
171 for (
const auto & elem :
as_range(beg, end))
172 global_index_map.
emplace(elem->id(), global_index[cnt++]);
176 libmesh_assert_equal_to (global_index_map.size(), n_range_elem);
179 std::unordered_set<dof_id_type> distinct_global_indices, distinct_ids;
180 for (
const auto & [elem_id, index] : global_index_map)
182 distinct_ids.insert(elem_id);
183 distinct_global_indices.insert(index);
185 libmesh_assert_equal_to (distinct_global_indices.size(), n_range_elem);
186 libmesh_assert_equal_to (distinct_ids.size(), n_range_elem);
194 typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
195 map_type interior_to_boundary_map;
197 for (
const auto & elem :
as_range(beg, end))
201 if ((elem->dim() >= LIBMESH_DIM) ||
202 !elem->interior_parent())
206 std::set<Elem *> neighbor_set;
207 elem->find_interior_neighbors(neighbor_set);
209 for (
auto & neighbor : neighbor_set)
210 interior_to_boundary_map.emplace(neighbor, elem);
214 std::vector<Metis::idx_t> part(n_range_elem);
218 if (
mesh.processor_id() == 0)
222 std::vector<Metis::idx_t> vwgt(n_range_elem);
225 n =
static_cast<Metis::idx_t
>(n_range_elem),
228 nparts =
static_cast<Metis::idx_t
>(n_pieces),
237 csr_graph.
offsets.resize(n_range_elem + 1, 0);
245#ifdef LIBMESH_ENABLE_AMR
246 std::vector<const Elem *> neighbors_offspring;
250 std::size_t graph_size=0;
255 for (
const auto & elem :
as_range(beg, end))
258 global_index_map[elem->id()];
260 libmesh_assert_less (elem_global_index, vwgt.size());
272 vwgt[elem_global_index] = 50;
274 vwgt[elem_global_index] = elem->n_nodes();
277 vwgt[elem_global_index] =
static_cast<Metis::idx_t
>((*_weights)[elem->id()]);
279 unsigned int num_neighbors = 0;
283 for (
auto neighbor : elem->neighbor_ptr_range())
285 if (neighbor !=
nullptr)
290 if (neighbor->active() && !global_index_map.
count(neighbor->id()))
295 if (neighbor->active())
298#ifdef LIBMESH_ENABLE_AMR
307 const unsigned int ns =
308 neighbor->which_neighbor_am_i (elem);
309 libmesh_assert_less (ns, neighbor->n_neighbors());
321 neighbor->active_family_tree (neighbors_offspring);
326 for (
const auto & child : neighbors_offspring)
329 if (!global_index_map.
count(child->id()))
335 if (child->neighbor_ptr(ns) == elem)
349 if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent())
352 std::set<const Elem *> neighbor_set;
353 elem->find_interior_neighbors(neighbor_set);
355 num_neighbors += cast_int<unsigned int>(neighbor_set.size());
359 typedef map_type::iterator map_it_type;
360 std::pair<map_it_type, map_it_type>
361 bounds = interior_to_boundary_map.equal_range(elem);
362 num_neighbors += cast_int<unsigned int>
363 (std::distance(bounds.first, bounds.second));
374 graph_size += num_neighbors;
381 for (
const auto & elem :
as_range(beg, end))
384 global_index_map[elem->id()];
386 unsigned int connection=0;
390 for (
auto neighbor : elem->neighbor_ptr_range())
392 if (neighbor !=
nullptr)
397 if (neighbor->active() && !global_index_map.
count(neighbor->id()))
402 if (neighbor->active())
403 csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()];
405#ifdef LIBMESH_ENABLE_AMR
414 const unsigned int ns =
415 neighbor->which_neighbor_am_i (elem);
416 libmesh_assert_less (ns, neighbor->n_neighbors());
420 neighbor->active_family_tree (neighbors_offspring);
425 for (
const auto & child : neighbors_offspring)
428 if (!global_index_map.
count(child->id()))
434 if (child->neighbor_ptr(ns) == elem)
438 csr_graph(elem_global_index, connection++) = global_index_map[child->id()];
448 if ((elem->dim() < LIBMESH_DIM) &&
449 elem->interior_parent())
452 std::set<const Elem *> neighbor_set;
453 elem->find_interior_neighbors(neighbor_set);
455 for (
const Elem * neighbor : neighbor_set)
463 const Elem * queried_elem =
mesh.query_elem_ptr(neighbor->id());
467 if (queried_elem && queried_elem == neighbor)
468 csr_graph(elem_global_index, connection++) =
469 libmesh_map_find(global_index_map, neighbor->id());
474 for (
const auto & pr :
as_range(interior_to_boundary_map.equal_range(elem)))
476 const Elem * neighbor = pr.second;
477 csr_graph(elem_global_index, connection++) =
478 global_index_map[neighbor->
id()];
484 libmesh_assert_equal_to (csr_graph.
vals.size(),
485 std::max(graph_size, std::size_t(1)));
488 Metis::idx_t ncon = 1;
494 Metis::METIS_PartGraphRecursive(&n,
497 csr_graph.
vals.data(),
510 Metis::METIS_PartGraphKway(&n,
513 csr_graph.
vals.data(),
527 mesh.comm().broadcast(part);
532 for (
auto & elem :
as_range(beg, end))
537 global_index_map[elem->id()];
539 libmesh_assert_less (elem_global_index, part.size());
543 elem->processor_id() = elem_procid;