21 #include "libmesh/libmesh_config.h"
22 #include "libmesh/mesh_base.h"
23 #include "libmesh/metis_partitioner.h"
24 #include "libmesh/libmesh_logging.h"
25 #include "libmesh/elem.h"
26 #include "libmesh/mesh_communication.h"
27 #include "libmesh/error_vector.h"
28 #include "libmesh/vectormap.h"
29 #include "libmesh/metis_csr_graph.h"
30 #include "libmesh/parallel.h"
31 #include "libmesh/utility.h"
33 #ifdef LIBMESH_HAVE_METIS
40 # include "libmesh/ignore_warnings.h"
42 # include "libmesh/restore_warnings.h"
46 # include "libmesh/sfc_partitioner.h"
51 #include <unordered_map>
61 unsigned int n_pieces)
73 libmesh_assert_greater (n_pieces, 0);
76 if (!
mesh.is_serial())
78 libMesh::out <<
"WARNING: Forced to gather a distributed mesh for METIS" << std::endl;
83 #ifndef LIBMESH_HAVE_METIS
86 libMesh::out <<
"ERROR: The library has been built without" << std::endl
87 <<
"Metis support. Using a space-filling curve" << std::endl
88 <<
"partitioner instead!" << std::endl;);
96 LOG_SCOPE(
"partition_range()",
"MetisPartitioner");
107 global_index_map.reserve (n_range_elem);
110 std::vector<dof_id_type> global_index;
114 beg,
end, global_index);
116 libmesh_assert_equal_to (global_index.size(), n_range_elem);
120 global_index_map.
insert (std::make_pair(elem->id(), global_index[cnt++]));
122 libmesh_assert_equal_to (global_index_map.size(), n_range_elem);
129 typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
130 map_type interior_to_boundary_map;
136 if ((elem->dim() >= LIBMESH_DIM) ||
137 !elem->interior_parent())
141 std::set<Elem *> neighbor_set;
142 elem->find_interior_neighbors(neighbor_set);
144 for (
auto & neighbor : neighbor_set)
145 interior_to_boundary_map.insert(std::make_pair(neighbor, elem));
149 std::vector<Metis::idx_t> part(n_range_elem);
153 if (
mesh.processor_id() == 0)
157 std::vector<Metis::idx_t> vwgt(n_range_elem);
160 n = static_cast<Metis::idx_t>(n_range_elem),
163 nparts = static_cast<Metis::idx_t>(n_pieces),
172 csr_graph.
offsets.resize(n_range_elem + 1, 0);
180 #ifdef LIBMESH_ENABLE_AMR
181 std::vector<const Elem *> neighbors_offspring;
185 std::size_t graph_size=0;
193 global_index_map[elem->id()];
195 libmesh_assert_less (elem_global_index, vwgt.size());
200 vwgt[elem_global_index] = elem->n_nodes();
202 vwgt[elem_global_index] = static_cast<Metis::idx_t>((*
_weights)[elem->id()]);
204 unsigned int num_neighbors = 0;
208 for (
auto neighbor : elem->neighbor_ptr_range())
210 if (neighbor !=
nullptr)
215 if (neighbor->active() && !global_index_map.
count(neighbor->id()))
220 if (neighbor->active())
223 #ifdef LIBMESH_ENABLE_AMR
232 const unsigned int ns =
233 neighbor->which_neighbor_am_i (elem);
234 libmesh_assert_less (ns, neighbor->n_neighbors());
246 neighbor->active_family_tree (neighbors_offspring);
251 for (
const auto & child : neighbors_offspring)
254 if (!global_index_map.
count(child->id()))
260 if (child->neighbor_ptr(ns) == elem)
274 if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent())
277 std::set<const Elem *> neighbor_set;
278 elem->find_interior_neighbors(neighbor_set);
280 num_neighbors += cast_int<unsigned int>(neighbor_set.size());
284 typedef map_type::iterator map_it_type;
285 std::pair<map_it_type, map_it_type>
286 bounds = interior_to_boundary_map.equal_range(elem);
287 num_neighbors += cast_int<unsigned int>
292 graph_size += num_neighbors;
302 global_index_map[elem->id()];
304 unsigned int connection=0;
308 for (
auto neighbor : elem->neighbor_ptr_range())
310 if (neighbor !=
nullptr)
315 if (neighbor->active() && !global_index_map.
count(neighbor->id()))
320 if (neighbor->active())
321 csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()];
323 #ifdef LIBMESH_ENABLE_AMR
332 const unsigned int ns =
333 neighbor->which_neighbor_am_i (elem);
334 libmesh_assert_less (ns, neighbor->n_neighbors());
338 neighbor->active_family_tree (neighbors_offspring);
343 for (
const auto & child : neighbors_offspring)
346 if (!global_index_map.
count(child->id()))
352 if (child->neighbor_ptr(ns) == elem)
356 csr_graph(elem_global_index, connection++) = global_index_map[child->id()];
366 if ((elem->dim() < LIBMESH_DIM) &&
367 elem->interior_parent())
370 std::set<const Elem *> neighbor_set;
371 elem->find_interior_neighbors(neighbor_set);
373 for (
const Elem * neighbor : neighbor_set)
381 const Elem * queried_elem =
mesh.query_elem_ptr(neighbor->id());
385 if (queried_elem && queried_elem == neighbor)
386 csr_graph(elem_global_index, connection++) =
387 libmesh_map_find(global_index_map, neighbor->id());
392 for (
const auto & pr :
as_range(interior_to_boundary_map.equal_range(elem)))
394 const Elem * neighbor = pr.second;
395 csr_graph(elem_global_index, connection++) =
396 global_index_map[neighbor->
id()];
402 libmesh_assert_equal_to (csr_graph.
vals.size(),
403 std::max(graph_size, std::size_t(1)));
406 Metis::idx_t ncon = 1;
412 Metis::METIS_PartGraphRecursive(&n,
415 csr_graph.
vals.data(),
428 Metis::METIS_PartGraphKway(&n,
431 csr_graph.
vals.data(),
445 mesh.comm().broadcast(part);
455 global_index_map[elem->id()];
457 libmesh_assert_less (elem_global_index, part.size());
459 static_cast<processor_id_type>(part[elem_global_index]);
461 elem->processor_id() = elem_procid;
469 const unsigned int n_pieces)
472 mesh.active_elements_begin(),
473 mesh.active_elements_end(),