#include <utils/ParMETISPartitioner.hpp> #include <utils/pugs_config.hpp> #ifdef PUGS_HAS_PARMETIS #include <utils/Exceptions.hpp> #include <utils/Messenger.hpp> #include <parmetis.h> #include <iostream> #include <vector> Array<int> ParMETISPartitioner::partition(const CRSGraph& graph) { std::cout << "Partitioning graph into " << rang::style::bold << parallel::size() << rang::style::reset << " parts using " << rang::fgB::green << "ParMETIS" << rang::fg::reset << '\n'; MPI_Group world_group; MPI_Comm_group(parallel::Messenger::getInstance().comm(), &world_group); MPI_Group mesh_group; std::vector<int> group_ranks = [&]() { Array<int> graph_node_owners = parallel::allGather(static_cast<int>(graph.numberOfNodes())); std::vector<int> grp_ranks; grp_ranks.reserve(graph_node_owners.size()); for (size_t i = 0; i < graph_node_owners.size(); ++i) { if (graph_node_owners[i] > 0) { grp_ranks.push_back(i); } } return grp_ranks; }(); MPI_Group_incl(world_group, group_ranks.size(), &(group_ranks[0]), &mesh_group); MPI_Comm partitioning_comm; MPI_Comm_create_group(parallel::Messenger::getInstance().comm(), mesh_group, 1, &partitioning_comm); Array<int> partition; if (graph.numberOfNodes() > 0) { int wgtflag = 0; int numflag = 0; int ncon = 1; int npart = parallel::size(); std::vector<float> tpwgts(npart, 1. / npart); std::vector<float> ubvec{1.05}; std::vector<int> options{1, 0, 0}; int edgecut = 0; int local_number_of_nodes = graph.numberOfNodes(); partition = Array<int>(local_number_of_nodes); std::vector<int> vtxdist{0, local_number_of_nodes}; const Array<const int>& entries = graph.entries(); const Array<const int>& neighbors = graph.neighbors(); int* entries_ptr = const_cast<int*>(&(entries[0])); int* neighbors_ptr = const_cast<int*>(&(neighbors[0])); int result = ParMETIS_V3_PartKway(&(vtxdist[0]), entries_ptr, neighbors_ptr, NULL, NULL, &wgtflag, &numflag, &ncon, &npart, &(tpwgts[0]), &(ubvec[0]), &(options[0]), &edgecut, &(partition[0]), &partitioning_comm); // LCOV_EXCL_START if (result == METIS_ERROR) { throw UnexpectedError("Metis Error"); } // LCOV_EXCL_STOP } MPI_Comm_free(&partitioning_comm); MPI_Group_free(&mesh_group); MPI_Group_free(&world_group); return partition; } #else // PUGS_HAS_PARMETIS Array<int> ParMETISPartitioner::partition(const CRSGraph& graph) { Array<int> partition{graph.entries().size() - 1}; partition.fill(0); return partition; } #endif // PUGS_HAS_PARMETIS