31 #ifdef LIBMESH_HAVE_METIS 49 #include <unordered_map> 59 unsigned int n_pieces)
71 libmesh_assert_greater (n_pieces, 0);
74 if (!
mesh.is_serial())
76 libMesh::out <<
"WARNING: Forced to gather a distributed mesh for METIS" << std::endl;
81 #ifndef LIBMESH_HAVE_METIS 84 libMesh::out <<
"ERROR: The library has been built without" << std::endl
85 <<
"Metis support. Using a space-filling curve" << std::endl
86 <<
"partitioner instead!" << std::endl;);
94 LOG_SCOPE(
"partition_range()",
"MetisPartitioner");
96 const dof_id_type n_range_elem = cast_int<dof_id_type>(std::distance(beg,
end));
105 global_index_map.reserve (n_range_elem);
108 std::vector<dof_id_type> global_index;
112 beg,
end, global_index);
114 libmesh_assert_equal_to (global_index.size(), n_range_elem);
118 global_index_map.insert (std::make_pair(elem->id(), global_index[cnt++]));
120 libmesh_assert_equal_to (global_index_map.size(), n_range_elem);
127 typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
128 map_type interior_to_boundary_map;
134 if ((elem->dim() >= LIBMESH_DIM) ||
135 !elem->interior_parent())
139 std::set<const Elem *> neighbor_set;
140 elem->find_interior_neighbors(neighbor_set);
142 std::set<const Elem *>::iterator n_it = neighbor_set.begin();
143 for (; n_it != neighbor_set.end(); ++n_it)
147 Elem * neighbor =
const_cast<Elem *
>(*n_it);
149 #if defined(LIBMESH_HAVE_UNORDERED_MULTIMAP) || \ 150 defined(LIBMESH_HAVE_TR1_UNORDERED_MULTIMAP) || \ 151 defined(LIBMESH_HAVE_HASH_MULTIMAP) || \ 152 defined(LIBMESH_HAVE_EXT_HASH_MULTIMAP) 153 interior_to_boundary_map.insert(std::make_pair(neighbor, elem));
155 interior_to_boundary_map.insert(interior_to_boundary_map.begin(),
156 std::make_pair(neighbor, elem));
162 std::vector<Metis::idx_t> part(n_range_elem);
166 if (
mesh.processor_id() == 0)
170 std::vector<Metis::idx_t> vwgt(n_range_elem);
173 n =
static_cast<Metis::idx_t
>(n_range_elem),
176 nparts = static_cast<Metis::idx_t>(n_pieces),
185 csr_graph.
offsets.resize(n_range_elem + 1, 0);
193 #ifdef LIBMESH_ENABLE_AMR 194 std::vector<const Elem *> neighbors_offspring;
198 std::size_t graph_size=0;
206 global_index_map[elem->id()];
208 libmesh_assert_less (elem_global_index, vwgt.size());
213 vwgt[elem_global_index] = elem->n_nodes();
215 vwgt[elem_global_index] =
static_cast<Metis::idx_t
>((*_weights)[elem->id()]);
217 unsigned int num_neighbors = 0;
221 for (
auto neighbor : elem->neighbor_ptr_range())
223 if (neighbor !=
nullptr)
228 if (neighbor->active() && !global_index_map.count(neighbor->id()))
233 if (neighbor->active())
236 #ifdef LIBMESH_ENABLE_AMR 245 const unsigned int ns =
246 neighbor->which_neighbor_am_i (elem);
247 libmesh_assert_less (ns, neighbor->n_neighbors());
259 neighbor->active_family_tree (neighbors_offspring);
264 for (std::size_t nc=0; nc<neighbors_offspring.size(); nc++)
267 neighbors_offspring[nc];
270 if (!global_index_map.count(child->
id()))
278 libmesh_assert (child->
active());
290 if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent())
293 std::set<const Elem *> neighbor_set;
296 num_neighbors += cast_int<unsigned int>(neighbor_set.size());
300 typedef map_type::iterator map_it_type;
301 std::pair<map_it_type, map_it_type>
302 bounds = interior_to_boundary_map.equal_range(elem);
303 num_neighbors += cast_int<unsigned int>
304 (std::distance(bounds.first, bounds.second));
308 graph_size += num_neighbors;
318 global_index_map[elem->id()];
320 unsigned int connection=0;
324 for (
auto neighbor : elem->neighbor_ptr_range())
326 if (neighbor !=
nullptr)
331 if (neighbor->active() && !global_index_map.count(neighbor->id()))
336 if (neighbor->active())
337 csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()];
339 #ifdef LIBMESH_ENABLE_AMR 348 const unsigned int ns =
349 neighbor->which_neighbor_am_i (elem);
350 libmesh_assert_less (ns, neighbor->n_neighbors());
354 neighbor->active_family_tree (neighbors_offspring);
359 for (std::size_t nc=0; nc<neighbors_offspring.size(); nc++)
362 neighbors_offspring[nc];
365 if (!global_index_map.count(child->
id()))
373 libmesh_assert (child->
active());
375 csr_graph(elem_global_index, connection++) = global_index_map[child->
id()];
385 if ((elem->dim() < LIBMESH_DIM) &&
386 elem->interior_parent())
389 std::set<const Elem *> neighbor_set;
390 elem->find_interior_neighbors(neighbor_set);
392 std::set<const Elem *>::iterator n_it = neighbor_set.begin();
393 for (; n_it != neighbor_set.end(); ++n_it)
395 const Elem * neighbor = *n_it;
403 const Elem * queried_elem =
mesh.query_elem_ptr(neighbor->
id());
407 if (queried_elem && queried_elem == neighbor)
410 global_index_map.find(neighbor->
id());
414 if (global_index_map_it == global_index_map.end())
415 libmesh_error_msg(
"Interior neighbor with id " << neighbor->
id() <<
" not found in global_index_map.");
418 csr_graph(elem_global_index, connection++) = global_index_map_it->second;
424 for (
const auto & pr :
as_range(interior_to_boundary_map.equal_range(elem)))
426 const Elem * neighbor = pr.second;
427 csr_graph(elem_global_index, connection++) =
428 global_index_map[neighbor->
id()];
434 libmesh_assert_equal_to (csr_graph.
vals.size(),
435 std::max(graph_size, std::size_t(1)));
438 Metis::idx_t ncon = 1;
444 Metis::METIS_PartGraphRecursive(&n,
447 csr_graph.
vals.data(),
460 Metis::METIS_PartGraphKway(&n,
463 csr_graph.
vals.data(),
477 mesh.comm().broadcast(part);
484 libmesh_assert (global_index_map.count(elem->id()));
487 global_index_map[elem->id()];
489 libmesh_assert_less (elem_global_index, part.size());
493 elem->processor_id() = elem_procid;
501 const unsigned int n_pieces)
504 mesh.active_elements_begin(),
505 mesh.active_elements_end(),
virtual void partition_range(MeshBase &mesh, MeshBase::element_iterator it, MeshBase::element_iterator end, const unsigned int n) override
void find_global_indices(const Parallel::Communicator &communicator, const libMesh::BoundingBox &, const ForwardIterator &, const ForwardIterator &, std::vector< dof_id_type > &) const
Compressed graph data structure used by MetisPartitioner.
void find_interior_neighbors(std::set< const Elem *> &neighbor_set) const
virtual void partition_range(MeshBase &mesh, MeshBase::element_iterator it, MeshBase::element_iterator end, const unsigned int n) override
The base class for all geometric element types.
uint8_t processor_id_type
long double max(long double a, double b)
std::vector< IndexType > offsets
void single_partition_range(MeshBase::element_iterator it, MeshBase::element_iterator end)
SimpleRange< I > as_range(const std::pair< I, I > &p)
std::vector< IndexType > vals
const Elem * neighbor_ptr(unsigned int i) const
virtual void _do_partition(MeshBase &mesh, const unsigned int n) override
Partitioner based on different types of space filling curves.
vector_type::iterator iterator
void prep_n_nonzeros(const libMesh::dof_id_type row, const libMesh::dof_id_type n_nonzeros_in)
OStreamProxy out(std::cout)