|
11 | 11 | #include <limits> |
12 | 12 | #include <map> |
13 | 13 | #include <stdexcept> |
| 14 | +#include <utility> |
14 | 15 |
|
15 | 16 | DomainDecomposition::DomainDecomposition() |
16 | 17 | : comm_(MPI_COMM_NULL), |
@@ -675,66 +676,114 @@ void DomainDecomposition::accumulate_ghost_forces(std::vector<LocalAtom>& owned_ |
675 | 676 |
|
676 | 677 | void DomainDecomposition::migrate_owned_atoms(std::vector<LocalAtom>& owned_atoms) const |
677 | 678 | { |
678 | | - std::vector<std::vector<PackedAtom> > send_atoms(static_cast<std::size_t>(size_)); |
679 | | - for (std::size_t i = 0; i < owned_atoms.size(); ++i) |
| 679 | + const int direction_count = 6; |
| 680 | + const int axis[direction_count] = {0, 0, 1, 1, 2, 2}; |
| 681 | + const int step[direction_count] = {-1, 1, -1, 1, -1, 1}; |
| 682 | + std::array<int, direction_count> neighbors; |
| 683 | + for (int idir = 0; idir < direction_count; ++idir) |
680 | 684 | { |
681 | | - LocalAtom atom = owned_atoms[i]; |
682 | | - atom.frac = wrapped_frac_from_cart(atom.cart); |
683 | | - atom.cart = atom.frac * latvec_; |
684 | | - atom.owner_rank = owner_rank_from_frac(atom.frac); |
685 | | - const std::array<int, 3> no_shift = {{0, 0, 0}}; |
686 | | - send_atoms[static_cast<std::size_t>(atom.owner_rank)].push_back(pack_atom(atom, no_shift)); |
| 685 | + std::array<int, 3> neighbor_coords = coords_; |
| 686 | + neighbor_coords[axis[idir]] = positive_mod(neighbor_coords[axis[idir]] + step[idir], dims_[axis[idir]]); |
| 687 | + neighbors[idir] = rank_from_coords(neighbor_coords); |
687 | 688 | } |
688 | 689 |
|
689 | | - std::vector<int> send_counts(static_cast<std::size_t>(size_), 0); |
690 | | - std::vector<int> recv_counts(static_cast<std::size_t>(size_), 0); |
691 | | - for (int irank = 0; irank < size_; ++irank) |
692 | | - { |
693 | | - send_counts[static_cast<std::size_t>(irank)] |
694 | | - = static_cast<int>(send_atoms[static_cast<std::size_t>(irank)].size() * sizeof(PackedAtom)); |
695 | | - } |
696 | | - MPI_Alltoall(&send_counts[0], 1, MPI_INT, &recv_counts[0], 1, MPI_INT, comm_); |
| 690 | + std::vector<LocalAtom> pending_atoms; |
| 691 | + pending_atoms.swap(owned_atoms); |
| 692 | + std::vector<LocalAtom> retained_atoms; |
| 693 | + retained_atoms.reserve(pending_atoms.size()); |
| 694 | + const std::array<int, 3> no_shift = {{0, 0, 0}}; |
697 | 695 |
|
698 | | - std::vector<int> send_displs(static_cast<std::size_t>(size_), 0); |
699 | | - std::vector<int> recv_displs(static_cast<std::size_t>(size_), 0); |
700 | | - int total_send_bytes = 0; |
701 | | - int total_recv_bytes = 0; |
702 | | - for (int irank = 0; irank < size_; ++irank) |
| 696 | + long long global_outgoing = 0; |
| 697 | + do |
703 | 698 | { |
704 | | - send_displs[static_cast<std::size_t>(irank)] = total_send_bytes; |
705 | | - recv_displs[static_cast<std::size_t>(irank)] = total_recv_bytes; |
706 | | - total_send_bytes += send_counts[static_cast<std::size_t>(irank)]; |
707 | | - total_recv_bytes += recv_counts[static_cast<std::size_t>(irank)]; |
708 | | - } |
| 699 | + std::array<std::vector<PackedAtom>, direction_count> send_atoms; |
| 700 | + for (std::size_t i = 0; i < pending_atoms.size(); ++i) |
| 701 | + { |
| 702 | + LocalAtom atom = std::move(pending_atoms[i]); |
| 703 | + atom.frac = wrapped_frac_from_cart(atom.cart); |
| 704 | + atom.cart = atom.frac * latvec_; |
709 | 705 |
|
710 | | - std::vector<PackedAtom> send_buffer(static_cast<std::size_t>(total_send_bytes / static_cast<int>(sizeof(PackedAtom)))); |
711 | | - int send_index = 0; |
712 | | - for (int irank = 0; irank < size_; ++irank) |
713 | | - { |
714 | | - const std::vector<PackedAtom>& atoms = send_atoms[static_cast<std::size_t>(irank)]; |
715 | | - for (std::size_t i = 0; i < atoms.size(); ++i) |
| 706 | + std::array<int, 3> owner_coords; |
| 707 | + const double frac[3] = {atom.frac.x, atom.frac.y, atom.frac.z}; |
| 708 | + for (int idim = 0; idim < 3; ++idim) |
| 709 | + { |
| 710 | + owner_coords[idim] = std::min(static_cast<int>(std::floor(frac[idim] * dims_[idim])), dims_[idim] - 1); |
| 711 | + } |
| 712 | + atom.owner_rank = rank_from_coords(owner_coords); |
| 713 | + if (atom.owner_rank == rank_) |
| 714 | + { |
| 715 | + retained_atoms.push_back(std::move(atom)); |
| 716 | + continue; |
| 717 | + } |
| 718 | + |
| 719 | + int direction = -1; |
| 720 | + for (int idim = 0; idim < 3 && direction < 0; ++idim) |
| 721 | + { |
| 722 | + int delta = owner_coords[idim] - coords_[idim]; |
| 723 | + if (delta > dims_[idim] / 2) delta -= dims_[idim]; |
| 724 | + if (delta < -dims_[idim] / 2) delta += dims_[idim]; |
| 725 | + if (delta != 0) direction = 2 * idim + (delta > 0 ? 1 : 0); |
| 726 | + } |
| 727 | + assert(direction >= 0); |
| 728 | + send_atoms[direction].push_back(pack_atom(atom, no_shift)); |
| 729 | + } |
| 730 | + pending_atoms.clear(); |
| 731 | + |
| 732 | + std::array<int, direction_count> send_counts; |
| 733 | + std::array<int, direction_count> recv_counts; |
| 734 | + long long local_outgoing = 0; |
| 735 | + for (int idir = 0; idir < direction_count; ++idir) |
716 | 736 | { |
717 | | - send_buffer[static_cast<std::size_t>(send_index++)] = atoms[i]; |
| 737 | + const std::size_t bytes = send_atoms[idir].size() * sizeof(PackedAtom); |
| 738 | + if (bytes > static_cast<std::size_t>(std::numeric_limits<int>::max())) |
| 739 | + { |
| 740 | + throw std::overflow_error("DomainDecomposition migration send count exceeds int range."); |
| 741 | + } |
| 742 | + send_counts[idir] = static_cast<int>(bytes); |
| 743 | + local_outgoing += static_cast<long long>(send_atoms[idir].size()); |
718 | 744 | } |
719 | | - } |
| 745 | + MPI_Allreduce(&local_outgoing, &global_outgoing, 1, MPI_LONG_LONG, MPI_SUM, comm_); |
| 746 | + if (global_outgoing == 0) break; |
720 | 747 |
|
721 | | - std::vector<PackedAtom> recv_buffer(static_cast<std::size_t>(total_recv_bytes / static_cast<int>(sizeof(PackedAtom)))); |
722 | | - MPI_Alltoallv(total_send_bytes > 0 ? reinterpret_cast<const char*>(&send_buffer[0]) : 0, |
723 | | - &send_counts[0], |
724 | | - &send_displs[0], |
725 | | - MPI_BYTE, |
726 | | - total_recv_bytes > 0 ? reinterpret_cast<char*>(&recv_buffer[0]) : 0, |
727 | | - &recv_counts[0], |
728 | | - &recv_displs[0], |
729 | | - MPI_BYTE, |
730 | | - comm_); |
| 748 | + std::array<MPI_Request, 2 * direction_count> requests; |
| 749 | + for (int idir = 0; idir < direction_count; ++idir) |
| 750 | + { |
| 751 | + const int opposite = idir ^ 1; |
| 752 | + MPI_Irecv(&recv_counts[idir], 1, MPI_INT, neighbors[idir], 100 + opposite, comm_, &requests[idir]); |
| 753 | + MPI_Isend(&send_counts[idir], 1, MPI_INT, neighbors[idir], 100 + idir, comm_, &requests[direction_count + idir]); |
| 754 | + } |
| 755 | + MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE); |
731 | 756 |
|
732 | | - owned_atoms.clear(); |
733 | | - owned_atoms.reserve(recv_buffer.size()); |
734 | | - for (std::size_t i = 0; i < recv_buffer.size(); ++i) |
735 | | - { |
736 | | - owned_atoms.push_back(unpack_owned_atom(recv_buffer[i])); |
737 | | - } |
| 757 | + std::array<std::vector<PackedAtom>, direction_count> recv_atoms; |
| 758 | + for (int idir = 0; idir < direction_count; ++idir) |
| 759 | + { |
| 760 | + if (recv_counts[idir] < 0 || recv_counts[idir] % static_cast<int>(sizeof(PackedAtom)) != 0) |
| 761 | + { |
| 762 | + throw std::runtime_error("Invalid DomainDecomposition migration receive count."); |
| 763 | + } |
| 764 | + recv_atoms[idir].resize(static_cast<std::size_t>(recv_counts[idir] / static_cast<int>(sizeof(PackedAtom)))); |
| 765 | + } |
| 766 | + |
| 767 | + for (int idir = 0; idir < direction_count; ++idir) |
| 768 | + { |
| 769 | + const int opposite = idir ^ 1; |
| 770 | + MPI_Irecv(recv_atoms[idir].empty() ? NULL : reinterpret_cast<char*>(&recv_atoms[idir][0]), |
| 771 | + recv_counts[idir], MPI_BYTE, neighbors[idir], 200 + opposite, comm_, &requests[idir]); |
| 772 | + MPI_Isend(send_atoms[idir].empty() ? NULL : reinterpret_cast<const char*>(&send_atoms[idir][0]), |
| 773 | + send_counts[idir], MPI_BYTE, neighbors[idir], 200 + idir, comm_, &requests[direction_count + idir]); |
| 774 | + } |
| 775 | + MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE); |
| 776 | + |
| 777 | + for (int idir = 0; idir < direction_count; ++idir) |
| 778 | + { |
| 779 | + for (std::size_t i = 0; i < recv_atoms[idir].size(); ++i) |
| 780 | + { |
| 781 | + pending_atoms.push_back(unpack_owned_atom(recv_atoms[idir][i])); |
| 782 | + } |
| 783 | + } |
| 784 | + } while (global_outgoing > 0); |
| 785 | + |
| 786 | + owned_atoms.swap(retained_atoms); |
738 | 787 | } |
739 | 788 |
|
740 | 789 | #endif // __MPI |
0 commit comments