-----------------------------------------------------------------------------
| 645 | } |
| 646 | //----------------------------------------------------------------------------- |
| 647 | std::tuple<std::int64_t, std::vector<std::int32_t>, |
| 648 | std::vector<std::vector<std::int64_t>>, |
| 649 | std::vector<std::vector<int>>> |
| 650 | common::stack_index_maps( |
| 651 | const std::vector<std::pair<std::reference_wrapper<const IndexMap>, int>>& |
| 652 | maps) |
| 653 | { |
| 654 | // Compute process offset for stacked index map |
| 655 | const std::int64_t process_offset = std::accumulate( |
| 656 | maps.begin(), maps.end(), std::int64_t(0), |
| 657 | [](std::int64_t c, auto& map) -> std::int64_t |
| 658 | { return c + map.first.get().local_range()[0] * map.second; }); |
| 659 | |
| 660 | // Get local offset (into new map) for each index map |
| 661 | std::vector<std::int32_t> local_sizes; |
| 662 | std::ranges::transform(maps, std::back_inserter(local_sizes), [](auto& map) |
| 663 | { return map.second * map.first.get().size_local(); }); |
| 664 | std::vector<std::int32_t> local_offset(local_sizes.size() + 1, 0); |
| 665 | std::partial_sum(local_sizes.begin(), local_sizes.end(), |
| 666 | std::next(local_offset.begin())); |
| 667 | |
| 668 | // Build list of src ranks (ranks that own ghosts) |
| 669 | std::set<int> src_set; |
| 670 | std::set<int> dest_set; |
| 671 | for (auto& [map, _] : maps) |
| 672 | { |
| 673 | std::span _src = map.get().src(); |
| 674 | std::span _dest = map.get().dest(); |
| 675 | src_set.insert(_src.begin(), _src.end()); |
| 676 | dest_set.insert(_dest.begin(), _dest.end()); |
| 677 | } |
| 678 | |
| 679 | std::vector<int> src(src_set.begin(), src_set.end()); |
| 680 | std::vector<int> dest(dest_set.begin(), dest_set.end()); |
| 681 | |
| 682 | // Create neighbour comms (0: ghost -> owner, 1: (owner -> ghost) |
| 683 | MPI_Comm comm0, comm1; |
| 684 | int ierr = MPI_Dist_graph_create_adjacent( |
| 685 | maps.at(0).first.get().comm(), dest.size(), dest.data(), MPI_UNWEIGHTED, |
| 686 | src.size(), src.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &comm0); |
| 687 | dolfinx::MPI::check_error(maps.at(0).first.get().comm(), ierr); |
| 688 | ierr = MPI_Dist_graph_create_adjacent( |
| 689 | maps.at(0).first.get().comm(), src.size(), src.data(), MPI_UNWEIGHTED, |
| 690 | dest.size(), dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &comm1); |
| 691 | dolfinx::MPI::check_error(maps.at(0).first.get().comm(), ierr); |
| 692 | |
| 693 | // NOTE: We could perform each MPI call just once rather than per map, |
| 694 | // but the complexity may not be worthwhile since this function is |
| 695 | // typically used for 'block' (rather the nested) problems, which is |
| 696 | // not the most efficient approach anyway. |
| 697 | |
| 698 | std::vector<std::vector<std::int64_t>> ghosts_new(maps.size()); |
| 699 | std::vector<std::vector<int>> ghost_owners_new(maps.size()); |
| 700 | |
| 701 | // For each map, send ghost indices to owner and owners send back the |
| 702 | // new index |
| 703 | for (std::size_t m = 0; m < maps.size(); ++m) |
| 704 | { |
nothing calls this directly
no test coverage detected