114 const unsigned int n_sbdmns)
117 libmesh_parallel_only(
mesh.comm());
125 this->single_partition(
mesh);
129 libmesh_assert_greater (n_sbdmns, 0);
132#ifndef LIBMESH_HAVE_PARMETIS
135 libMesh::out <<
"ERROR: The library has been built without" << std::endl
136 <<
"Parmetis support. Using a Metis" << std::endl
137 <<
"partitioner instead!" << std::endl;);
149 mesh.active_elements_end(), n_sbdmns);
155 if (
mesh.n_processors() == 1)
165 mesh.active_elements_end(), n_sbdmns);
169 LOG_SCOPE(
"repartition()",
"ParmetisPartitioner");
175 this->build_graph (
mesh);
182 bool ready_for_parmetis =
true;
183 for (
const auto & nelem : _n_active_elem_on_proc)
185 ready_for_parmetis =
false;
187 std::size_t my_adjacency = _pmetis->adjncy.size();
188 mesh.comm().min(my_adjacency);
190 ready_for_parmetis =
false;
195 if (!ready_for_parmetis)
207 std::vector<Parmetis::idx_t> vsize(_pmetis->vwgt.size(), 1);
208 Parmetis::real_t itr = 1000000.0;
209 MPI_Comm mpi_comm =
mesh.comm().get();
214 Parmetis::ParMETIS_V3_AdaptiveRepart(_pmetis->vtxdist.empty() ?
nullptr : _pmetis->vtxdist.data(),
215 _pmetis->xadj.empty() ? nullptr : _pmetis->xadj.data(),
216 _pmetis->adjncy.empty() ? nullptr : _pmetis->adjncy.data(),
217 _pmetis->vwgt.empty() ? nullptr : _pmetis->vwgt.data(),
218 vsize.empty() ? nullptr : vsize.data(),
224 _pmetis->tpwgts.empty() ? nullptr : _pmetis->tpwgts.data(),
225 _pmetis->ubvec.empty() ? nullptr : _pmetis->ubvec.data(),
227 _pmetis->options.data(),
229 _pmetis->part.empty() ? nullptr :
reinterpret_cast<Parmetis::idx_t *
>(_pmetis->part.data()),
233 this->assign_partitioning (
mesh, _pmetis->part);
245 const unsigned int n_sbdmns)
247 LOG_SCOPE(
"initialize()",
"ParmetisPartitioner");
251 _pmetis->wgtflag = 2;
253 _pmetis->numflag = 0;
254 _pmetis->nparts =
static_cast<Parmetis::idx_t
>(n_sbdmns);
255 _pmetis->edgecut = 0;
259 _pmetis->vtxdist.assign (
mesh.n_processors()+1, 0);
260 _pmetis->tpwgts.assign (_pmetis->nparts, 1./_pmetis->nparts);
261 _pmetis->ubvec.assign (_pmetis->ncon, 1.05);
262 _pmetis->part.assign (n_active_local_elem, 0);
263 _pmetis->options.resize (5);
264 _pmetis->vwgt.resize (n_active_local_elem);
267 _pmetis->options[0] = 1;
268 _pmetis->options[1] = 0;
269 _pmetis->options[2] = 15;
270 _pmetis->options[3] = 2;
282 MeshTools::create_bounding_box(
mesh);
284 _find_global_index_by_pid_map(
mesh);
296 libmesh_assert_equal_to (_pmetis->vtxdist.size(),
297 cast_int<std::size_t>(
mesh.n_processors()+1));
298 libmesh_assert_equal_to (_pmetis->vtxdist[0], 0);
302 _pmetis->vtxdist[pid+1] = _pmetis->vtxdist[pid] + _n_active_elem_on_proc[pid];
303 n_active_elem += _n_active_elem_on_proc[pid];
305 libmesh_assert_equal_to (_pmetis->vtxdist.back(),
static_cast<Parmetis::idx_t
>(n_active_elem));
310 std::unordered_map<dof_id_type, dof_id_type> global_index_map;
313 std::vector<dof_id_type> global_index;
328 const Elem * elem = *it;
332 libmesh_assert_less (cnt, global_index.size());
333 libmesh_assert_less (global_index[cnt], n_active_elem);
335 global_index_map.emplace(elem->
id(), global_index[cnt++]);
339 libmesh_assert_less_equal (global_index_map.size(), n_active_elem);
340 libmesh_assert_less_equal (_global_index_by_pid_map.size(), n_active_elem);
346 libmesh_error_msg_if(global_index_map.size() != _global_index_by_pid_map.size(),
347 "ERROR: ParmetisPartitioner cannot handle unpartitioned objects!");
354 std::vector<dof_id_type> subdomain_bounds(
mesh.n_processors());
356 const dof_id_type first_local_elem = _pmetis->vtxdist[
mesh.processor_id()];
363 if (pid <
static_cast<unsigned int>(_pmetis->nparts))
365 tgt_subdomain_size = n_active_elem/std::min
366 (cast_int<Parmetis::idx_t>(
mesh.n_processors()), _pmetis->nparts);
368 if (pid < n_active_elem%_pmetis->nparts)
369 tgt_subdomain_size++;
372 subdomain_bounds[0] = tgt_subdomain_size;
374 subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
377 libmesh_assert_equal_to (subdomain_bounds.back(), n_active_elem);
379 Threads::parallel_for
380 (
mesh.active_local_element_stored_range(),
381 [first_local_elem, n_active_elem, n_active_local_elem,
this,
382 &global_index_map, &subdomain_bounds](
const ConstElemRange & range)
384 for (const Elem * elem : range)
386 const dof_id_type global_index_by_pid =
387 libmesh_map_find(_global_index_by_pid_map, elem->id());
388 libmesh_assert_less (global_index_by_pid, n_active_elem);
390 const dof_id_type local_index =
391 global_index_by_pid - first_local_elem;
393 libmesh_assert_less (local_index, n_active_local_elem);
394 libmesh_assert_less (local_index, _pmetis->vwgt.size());
396 libmesh_ignore(n_active_elem);
397 libmesh_ignore(n_active_local_elem);
404 if (elem->type() == NODEELEM &&
405 elem->mapping_type() == RATIONAL_BERNSTEIN_MAP)
406 _pmetis->vwgt[local_index] = 50;
408 _pmetis->vwgt[local_index] = elem->n_nodes();
411 const dof_id_type global_index =
412 libmesh_map_find(global_index_map, elem->id());
414 libmesh_assert_less (global_index, subdomain_bounds.back());
416 const unsigned int subdomain_id =
417 cast_int<unsigned int>
418 (std::distance(subdomain_bounds.begin(),
419 std::lower_bound(subdomain_bounds.begin(),
420 subdomain_bounds.end(),
422 libmesh_assert_less (subdomain_id, _pmetis->nparts);
423 libmesh_assert_less (local_index, _pmetis->part.size());
425 _pmetis->part[local_index] = subdomain_id;
435 LOG_SCOPE(
"build_graph()",
"ParmetisPartitioner");
442 Partitioner::build_graph(
mesh);
446 for (
auto & row: _dual_graph)
447 graph_size_upper_bound += cast_int<dof_id_type>(row.size());
450 _pmetis->xadj.clear();
451 _pmetis->xadj.reserve (n_active_local_elem + 1);
452 _pmetis->adjncy.clear();
453 _pmetis->adjncy.reserve (graph_size_upper_bound);
456 _pmetis->vtxdist[
mesh.processor_id()];
457 std::unordered_set<dof_id_type> unique_neighbors;
463 _pmetis->xadj.push_back(cast_int<int>(_pmetis->adjncy.size()));
466 first_local_elem + cast_int<dof_id_type>(i);
467 const auto & graph_row = _dual_graph[i];
468 unique_neighbors.clear();
470 for (
const auto neighbor : graph_row)
471 if (neighbor != global_index &&
472 unique_neighbors.insert(neighbor).second)
473 _pmetis->adjncy.push_back(neighbor);
477 _pmetis->xadj.push_back(cast_int<int>(_pmetis->adjncy.size()));
479 libmesh_assert_equal_to (_pmetis->xadj.size(), n_active_local_elem+1);
480 libmesh_assert_less_equal (_pmetis->adjncy.size(),
481 graph_size_upper_bound);
void initialize(EquationSystems &es, const std::string &system_name)