1111#include < cstdint>
1212#include < functional>
1313#include < numeric>
14+ #include < ranges>
1415#include < span>
1516#include < utility>
1617#include < vector>
@@ -182,9 +183,9 @@ compute_submap_indices(const IndexMap& imap,
182183 std::ranges::for_each (indices,
183184 [&is_in_submap](auto i) { is_in_submap[i] = 1 ; });
184185
185- // --- Step 1 ---: Send ghost indices in `indices` to their owners
186- // and receive indices owned by this process that are in `indices`
187- // on other processes
186+ // --- Step 1 ---: Send ghost indices in `indices` to their owners and
187+ // receive indices owned by this process that are in `indices` on
188+ // other processes.
188189 const auto [send_indices, recv_indices, ghost_buffer_pos, send_sizes,
189190 recv_sizes, send_disp, recv_disp]
190191 = communicate_ghosts_to_owners (
@@ -198,7 +199,7 @@ compute_submap_indices(const IndexMap& imap,
198199 // all indices in `recv_indices` will necessarily be in `indices` on
199200 // this process, and thus other processes must own them in the submap.
200201 // If ownership of received index doesn't change, then this process
201- // has the receiving rank as a destination
202+ // has the receiving rank as a destination.
202203 std::vector<int > recv_owners (send_disp.back ());
203204 std::vector<int > submap_dest;
204205 submap_dest.reserve (1 );
@@ -571,7 +572,7 @@ common::compute_owned_indices(std::span<const std::int32_t> indices,
571572 std::vector<int > send_sizes (src.size (), 0 );
572573 std::vector<int > send_disp (src.size () + 1 , 0 );
573574 auto it = ghost_owners.begin ();
574- for (std::size_t i = 0 ; i < src.size (); i++ )
575+ for (std::size_t i = 0 ; i < src.size (); ++i )
575576 {
576577 int owner = src[i];
577578 auto begin = std::find (it, ghost_owners.end (), owner);
@@ -850,7 +851,6 @@ common::create_sub_index_map(const IndexMap& imap,
850851 submap_ghost_gidxs, submap_ghost_owners),
851852 std::move (sub_imap_to_imap)};
852853}
853-
854854// -----------------------------------------------------------------------------
855855// -----------------------------------------------------------------------------
856856IndexMap::IndexMap (MPI_Comm comm, std::int32_t local_size) : _comm(comm, true )
@@ -1112,7 +1112,6 @@ graph::AdjacencyList<int> IndexMap::index_to_dest_ranks(int tag) const
11121112 // (index, [sharing ranks]). Non-owned indices are ghosted but
11131113 // not owned by this rank.
11141114 {
1115-
11161115 // Send data for owned indices back to ghosting ranks (this is
11171116 // necessary to share with ghosting ranks all the ranks that also
11181117 // ghost a ghost index)
@@ -1302,35 +1301,76 @@ std::span<const int> IndexMap::src() const noexcept { return _src; }
13021301// -----------------------------------------------------------------------------
13031302std::span<const int > IndexMap::dest () const noexcept { return _dest; }
13041303// -----------------------------------------------------------------------------
1305- std::array<double , 2 > IndexMap::imbalance () const
1304+ std::vector<std::int32_t > IndexMap::weights_src () const
1305+ {
1306+ std::vector<std::int32_t > weights (_src.size (), 0 );
1307+ for (int r : _owners)
1308+ {
1309+ auto it = std::ranges::lower_bound (_src, r);
1310+ assert (it != _src.end () and *it == r);
1311+ std::size_t pos = std::distance (_src.begin (), it);
1312+ assert (pos < weights.size ());
1313+ weights[pos] += 1 ;
1314+ }
1315+
1316+ return weights;
1317+ }
1318+ // -----------------------------------------------------------------------------
1319+ std::vector<std::int32_t > IndexMap::weights_dest () const
1320+ {
1321+ int ierr = 0 ;
1322+ std::vector<std::int32_t > w_src = this ->weights_src ();
1323+
1324+ std::vector<MPI_Request> requests (_dest.size () + _src.size ());
1325+
1326+ std::vector<std::int32_t > w_dest (_dest.size ());
1327+ for (std::size_t i = 0 ; i < _dest.size (); ++i)
1328+ {
1329+ ierr = MPI_Irecv (w_dest.data () + i, 1 , MPI_INT32_T, _dest[i], MPI_ANY_TAG,
1330+ _comm.comm (), &requests[i]);
1331+ dolfinx::MPI::check_error (_comm.comm (), ierr);
1332+ }
1333+
1334+ for (std::size_t i = 0 ; i < _src.size (); ++i)
1335+ {
1336+ ierr = MPI_Isend (w_src.data () + i, 1 , MPI_INT32_T, _src[i], 0 , _comm.comm (),
1337+ &requests[i + _dest.size ()]);
1338+ dolfinx::MPI::check_error (_comm.comm (), ierr);
1339+ }
1340+
1341+ ierr = MPI_Waitall (requests.size (), requests.data (), MPI_STATUS_IGNORE);
1342+ dolfinx::MPI::check_error (_comm.comm (), ierr);
1343+
1344+ return w_dest;
1345+ }
1346+ // -----------------------------------------------------------------------------
1347+ std::array<std::vector<int >, 2 > IndexMap::rank_type (int split_type) const
13061348{
1307- std::array<double , 2 > imbalance{-1 ., -1 .};
1308- std::array<std::int32_t , 2 > max_count;
1309- std::array<std::int32_t , 2 > local_sizes
1310- = {static_cast <std::int32_t >(_local_range[1 ] - _local_range[0 ]),
1311- static_cast <std::int32_t >(_ghosts.size ())};
1312-
1313- // Find the maximum number of owned indices and the maximum number of ghost
1314- // indices across all processes.
1315- MPI_Allreduce (local_sizes.data (), max_count.data (), 2 , MPI_INT32_T, MPI_MAX,
1316- _comm.comm ());
1317-
1318- std::int32_t total_num_ghosts = 0 ;
1319- MPI_Allreduce (&local_sizes[1 ], &total_num_ghosts, 1 , MPI_INT32_T, MPI_SUM,
1320- _comm.comm ());
1321-
1322- // Compute the average number of owned and ghost indices per process.
1323- int comm_size = dolfinx::MPI::size (_comm.comm ());
1324- double avg_owned = static_cast <double >(_size_global) / comm_size;
1325- double avg_ghosts = static_cast <double >(total_num_ghosts) / comm_size;
1326-
1327- // Compute the imbalance by dividing the maximum number of indices by the
1328- // corresponding average.
1329- if (avg_owned > 0 )
1330- imbalance[0 ] = max_count[0 ] / avg_owned;
1331- if (avg_ghosts > 0 )
1332- imbalance[1 ] = max_count[1 ] / avg_ghosts;
1333-
1334- return imbalance;
1349+ int ierr;
1350+
1351+ MPI_Comm comm_s;
1352+ ierr = MPI_Comm_split_type (_comm.comm (), split_type, 0 , MPI_INFO_NULL,
1353+ &comm_s);
1354+ dolfinx::MPI::check_error (_comm.comm (), ierr);
1355+
1356+ int size_s = dolfinx::MPI::size (comm_s);
1357+ int rank = dolfinx::MPI::rank (_comm.comm ());
1358+
1359+ // Note: in most cases, size_s will be much smaller than the size of
1360+ // _comm
1361+ std::vector<int > ranks_s (size_s);
1362+ ierr = MPI_Allgather (&rank, 1 , MPI_INT, ranks_s.data (), 1 , MPI_INT, comm_s);
1363+ dolfinx::MPI::check_error (comm_s, ierr);
1364+
1365+ std::vector<int > split_dest, split_src;
1366+ std::ranges::set_intersection (_dest, ranks_s, std::back_inserter (split_dest));
1367+ assert (std::ranges::is_sorted (split_dest));
1368+ std::ranges::set_intersection (_src, ranks_s, std::back_inserter (split_src));
1369+ assert (std::ranges::is_sorted (split_src));
1370+
1371+ ierr = MPI_Comm_free (&comm_s);
1372+ dolfinx::MPI::check_error (comm_s, ierr);
1373+
1374+ return {std::move (split_dest), std::move (split_src)};
13351375}
13361376// -----------------------------------------------------------------------------
0 commit comments