16#ifndef CABANA_COMMUNICATIONPLAN_HPP
17#define CABANA_COMMUNICATIONPLAN_HPP
21#include <Kokkos_Core.hpp>
22#include <Kokkos_ScatterView.hpp>
58struct CountSendsAndCreateSteeringDuplicated
61struct CountSendsAndCreateSteeringAtomic
67template <
class ExecutionSpace>
68struct CountSendsAndCreateSteeringAlgorithm;
71#ifdef KOKKOS_ENABLE_CUDA
73struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Cuda>
75 using type = CountSendsAndCreateSteeringAtomic;
78#ifdef KOKKOS_ENABLE_HIP
80struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Experimental::HIP>
82 using type = CountSendsAndCreateSteeringAtomic;
85#ifdef KOKKOS_ENABLE_SYCL
87struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Experimental::SYCL>
89 using type = CountSendsAndCreateSteeringAtomic;
92#ifdef KOKKOS_ENABLE_OPENMPTARGET
94struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Experimental::OpenMPTarget>
96 using type = CountSendsAndCreateSteeringAtomic;
101template <
class ExecutionSpace>
102struct CountSendsAndCreateSteeringAlgorithm
104 using type = CountSendsAndCreateSteeringDuplicated;
109template <
class ExecutionSpace,
class ExportRankView>
110auto countSendsAndCreateSteering( ExecutionSpace,
111 const ExportRankView element_export_ranks,
113 CountSendsAndCreateSteeringAtomic )
114 -> std::pair<Kokkos::View<int*, typename ExportRankView::memory_space>,
115 Kokkos::View<
typename ExportRankView::size_type*,
116 typename ExportRankView::memory_space>>
118 using memory_space =
typename ExportRankView::memory_space;
119 using size_type =
typename ExportRankView::size_type;
122 Kokkos::View<int*, memory_space> neighbor_counts(
"neighbor_counts",
124 Kokkos::View<size_type*, memory_space> neighbor_ids(
125 Kokkos::ViewAllocateWithoutInitializing(
"neighbor_ids" ),
126 element_export_ranks.size() );
132 if ( comm_size <= 64 )
134 constexpr int team_size = 256;
135 Kokkos::TeamPolicy<ExecutionSpace> team_policy(
136 ( element_export_ranks.size() + team_size - 1 ) / team_size,
138 team_policy = team_policy.set_scratch_size(
140 Kokkos::PerTeam(
sizeof(
int ) * ( team_size + 2 * comm_size ) ) );
141 Kokkos::parallel_for(
142 "Cabana::CommunicationPlan::countSendsAndCreateSteeringShared",
145 const typename Kokkos::TeamPolicy<ExecutionSpace>::member_type&
153 int* scratch = (
int*)team.team_shmem().get_shmem(
154 ( team.team_size() + 2 * comm_size ) *
sizeof(
int ), 0 );
158 int* local_neighbor_ids = scratch;
160 int* histo = local_neighbor_ids + team.team_size();
162 int* global_offset = histo + comm_size;
165 team.team_rank() + team.league_rank() * team.team_size();
167 const int local_id = team.team_rank();
169 const int num_elements = element_export_ranks.size();
171 const int my_element_export_rank =
172 ( tid < num_elements ? element_export_ranks( tid ) : -1 );
176 const bool in_bounds =
177 tid < num_elements && my_element_export_rank >= 0;
179 Kokkos::parallel_for(
180 Kokkos::TeamThreadRange( team, comm_size ),
181 [&](
const int i ) { histo[i] = 0; } );
190 local_neighbor_ids[local_id] = Kokkos::atomic_fetch_add(
191 &histo[my_element_export_rank], 1 );
198 Kokkos::parallel_for(
199 Kokkos::TeamThreadRange( team, comm_size ),
203 global_offset[i] = Kokkos::atomic_fetch_add(
204 &neighbor_counts( i ), histo[i] );
213 neighbor_ids( tid ) =
214 global_offset[my_element_export_rank] +
215 local_neighbor_ids[local_id];
224 Kokkos::parallel_for(
225 "Cabana::CommunicationPlan::countSendsAndCreateSteering",
226 Kokkos::RangePolicy<ExecutionSpace>( 0,
227 element_export_ranks.size() ),
228 KOKKOS_LAMBDA(
const size_type i ) {
229 if ( element_export_ranks( i ) >= 0 )
230 neighbor_ids( i ) = Kokkos::atomic_fetch_add(
231 &neighbor_counts( element_export_ranks( i ) ), 1 );
237 return std::make_pair( neighbor_counts, neighbor_ids );
242template <
class ExecutionSpace,
class ExportRankView>
243auto countSendsAndCreateSteering( ExecutionSpace,
244 const ExportRankView element_export_ranks,
246 CountSendsAndCreateSteeringDuplicated )
247 -> std::pair<Kokkos::View<int*, typename ExportRankView::memory_space>,
248 Kokkos::View<
typename ExportRankView::size_type*,
249 typename ExportRankView::memory_space>>
251 using memory_space =
typename ExportRankView::memory_space;
252 using size_type =
typename ExportRankView::size_type;
255 Kokkos::Experimental::UniqueToken<
256 ExecutionSpace, Kokkos::Experimental::UniqueTokenScope::Global>
260 Kokkos::View<int*, memory_space> neighbor_counts(
261 Kokkos::ViewAllocateWithoutInitializing(
"neighbor_counts" ),
263 Kokkos::View<size_type*, memory_space> neighbor_ids(
264 Kokkos::ViewAllocateWithoutInitializing(
"neighbor_ids" ),
265 element_export_ranks.size() );
266 Kokkos::View<int**, memory_space> neighbor_counts_dup(
267 "neighbor_counts", unique_token.size(), comm_size );
268 Kokkos::View<size_type**, memory_space> neighbor_ids_dup(
269 "neighbor_ids", unique_token.size(), element_export_ranks.size() );
272 Kokkos::parallel_for(
273 "Cabana::CommunicationPlan::intialCount",
274 Kokkos::RangePolicy<ExecutionSpace>( 0, element_export_ranks.size() ),
275 KOKKOS_LAMBDA(
const size_type i ) {
276 if ( element_export_ranks( i ) >= 0 )
279 auto thread_id = unique_token.acquire();
289 neighbor_ids_dup( thread_id, i ) = ++neighbor_counts_dup(
290 thread_id, element_export_ranks( i ) );
293 unique_token.release( thread_id );
300 Kokkos::TeamPolicy<ExecutionSpace, Kokkos::Schedule<Kokkos::Dynamic>>;
301 using index_type =
typename team_policy::index_type;
305 Kokkos::parallel_for(
306 "Cabana::CommunicationPlan::finalCount",
307 team_policy( neighbor_counts.extent( 0 ), Kokkos::AUTO ),
308 KOKKOS_LAMBDA(
const typename team_policy::member_type& team ) {
310 auto i = team.league_rank();
313 int thread_counts = 0;
314 Kokkos::parallel_reduce(
315 Kokkos::TeamThreadRange( team,
316 neighbor_counts_dup.extent( 0 ) ),
317 [&](
const index_type thread_id,
int& result )
318 { result += neighbor_counts_dup( thread_id, i ); },
320 neighbor_counts( i ) = thread_counts;
326 Kokkos::parallel_for(
327 "Cabana::CommunicationPlan::createSteering",
328 team_policy( element_export_ranks.size(), Kokkos::AUTO ),
329 KOKKOS_LAMBDA(
const typename team_policy::member_type& team ) {
331 auto i = team.league_rank();
334 if ( element_export_ranks( i ) >= 0 )
339 index_type dup_thread = 0;
340 Kokkos::parallel_reduce(
341 Kokkos::TeamThreadRange( team,
342 neighbor_ids_dup.extent( 0 ) ),
343 [&](
const index_type thread_id, index_type& result )
345 if ( neighbor_ids_dup( thread_id, i ) > 0 )
355 size_type thread_offset = 0;
356 Kokkos::parallel_reduce(
357 Kokkos::TeamThreadRange( team, dup_thread ),
358 [&](
const index_type thread_id, size_type& result ) {
359 result += neighbor_counts_dup(
360 thread_id, element_export_ranks( i ) );
368 thread_offset + neighbor_ids_dup( dup_thread, i ) - 1;
374 return std::make_pair( neighbor_counts, neighbor_ids );
389 std::vector<int> topology )
391 auto remove_end = std::remove( topology.begin(), topology.end(), -1 );
392 std::sort( topology.begin(), remove_end );
393 auto unique_end = std::unique( topology.begin(), remove_end );
394 topology.resize( std::distance( topology.begin(), unique_end ) );
398 MPI_Comm_rank( comm, &my_rank );
399 for (
auto& n : topology )
403 std::swap( n, topology[0] );
436template <
class MemorySpace>
442 static_assert( Kokkos::is_memory_space<MemorySpace>() );
451 using size_type =
typename memory_space::memory_space::size_type;
465 auto p = std::make_unique<MPI_Comm>();
466 MPI_Comm_dup(
comm, p.get() );
480 MPI_Comm
comm()
const {
return *_comm_ptr; }
496 return _neighbors[neighbor];
509 return _num_export[neighbor];
529 return _num_import[neighbor];
549 std::size_t
exportSize()
const {
return _num_export_element; }
562 return _export_steering;
606 template <
class ExecutionSpace,
class RankViewType>
607 Kokkos::View<size_type*, memory_space>
609 const RankViewType& element_export_ranks,
610 const std::vector<int>& neighbor_ranks )
615 _num_export_element = element_export_ranks.size();
619 int num_n = _neighbors.size();
623 MPI_Comm_size(
comm(), &comm_size );
627 MPI_Comm_rank(
comm(), &my_rank );
631 const int mpi_tag = 1221;
634 _num_export.assign( num_n, 0 );
635 _num_import.assign( num_n, 0 );
639 auto counts_and_ids = Impl::countSendsAndCreateSteering(
640 exec_space, element_export_ranks, comm_size,
641 typename Impl::CountSendsAndCreateSteeringAlgorithm<
642 ExecutionSpace>::type() );
645 auto neighbor_counts_host = Kokkos::create_mirror_view_and_copy(
646 Kokkos::HostSpace(), counts_and_ids.first );
649 for (
int n = 0; n < num_n; ++n )
650 _num_export[n] = neighbor_counts_host( _neighbors[n] );
653 std::vector<MPI_Request> requests;
654 requests.reserve( num_n );
655 for (
int n = 0; n < num_n; ++n )
656 if ( my_rank != _neighbors[n] )
658 requests.push_back( MPI_Request() );
659 MPI_Irecv( &_num_import[n], 1, MPI_UNSIGNED_LONG, _neighbors[n],
660 mpi_tag,
comm(), &( requests.back() ) );
663 _num_import[n] = _num_export[n];
666 for (
int n = 0; n < num_n; ++n )
667 if ( my_rank != _neighbors[n] )
668 MPI_Send( &_num_export[n], 1, MPI_UNSIGNED_LONG, _neighbors[n],
672 std::vector<MPI_Status> status( requests.size() );
674 MPI_Waitall( requests.size(), requests.data(), status.data() );
675 if ( MPI_SUCCESS != ec )
676 throw std::logic_error(
677 "Cabana::CommunicationPlan::createFromExportsAndTopology: "
678 "Failed MPI Communication" );
681 _total_num_export = std::accumulate(
682 _num_export.begin(), _num_export.end(), std::size_t{ 0u } );
683 _total_num_import = std::accumulate(
684 _num_import.begin(), _num_import.end(), std::size_t{ 0u } );
690 return counts_and_ids.second;
728 template <
class RankViewType>
729 Kokkos::View<size_type*, memory_space>
731 const std::vector<int>& neighbor_ranks )
735 element_export_ranks, neighbor_ranks );
768 template <
class ExecutionSpace,
class RankViewType>
769 Kokkos::View<size_type*, memory_space>
771 const RankViewType& element_export_ranks )
776 _num_export_element = element_export_ranks.size();
780 MPI_Comm_size(
comm(), &comm_size );
784 MPI_Comm_rank(
comm(), &my_rank );
788 const int mpi_tag = 1221;
792 auto counts_and_ids = Impl::countSendsAndCreateSteering(
793 exec_space, element_export_ranks, comm_size,
794 typename Impl::CountSendsAndCreateSteeringAlgorithm<
795 ExecutionSpace>::type() );
798 auto neighbor_counts_host = Kokkos::create_mirror_view_and_copy(
799 Kokkos::HostSpace(), counts_and_ids.first );
805 _total_num_export = 0;
806 for (
int r = 0; r < comm_size; ++r )
807 if ( neighbor_counts_host( r ) > 0 )
809 _neighbors.push_back( r );
810 _num_export.push_back( neighbor_counts_host( r ) );
811 _total_num_export += neighbor_counts_host( r );
812 neighbor_counts_host( r ) = 1;
817 int num_export_rank = _neighbors.size();
818 _num_import.assign( num_export_rank, 0 );
822 bool self_send =
false;
823 for (
int n = 0; n < num_export_rank; ++n )
824 if ( _neighbors[n] == my_rank )
826 std::swap( _neighbors[n], _neighbors[0] );
827 std::swap( _num_export[n], _num_export[0] );
828 _num_import[0] = _num_export[0];
834 int num_import_rank = -1;
835 std::vector<int> recv_counts( comm_size, 1 );
836 MPI_Reduce_scatter( neighbor_counts_host.data(), &num_import_rank,
837 recv_counts.data(), MPI_INT, MPI_SUM,
comm() );
843 std::vector<std::size_t> import_sizes( num_import_rank );
844 std::vector<MPI_Request> requests( num_import_rank );
845 for (
int n = 0; n < num_import_rank; ++n )
846 MPI_Irecv( &import_sizes[n], 1, MPI_UNSIGNED_LONG, MPI_ANY_SOURCE,
847 mpi_tag,
comm(), &requests[n] );
850 int self_offset = ( self_send ) ? 1 : 0;
851 for (
int n = self_offset; n < num_export_rank; ++n )
852 MPI_Send( &_num_export[n], 1, MPI_UNSIGNED_LONG, _neighbors[n],
856 std::vector<MPI_Status> status( requests.size() );
858 MPI_Waitall( requests.size(), requests.data(), status.data() );
859 if ( MPI_SUCCESS != ec )
860 throw std::logic_error(
861 "Cabana::CommunicationPlan::createFromExportsOnly: Failed MPI "
866 std::accumulate( import_sizes.begin(), import_sizes.end(),
867 ( self_send ) ? _num_import[0] : 0 );
871 for (
int i = 0; i < num_import_rank; ++i )
874 const auto source = status[i].MPI_SOURCE;
878 auto found_neighbor =
879 std::find( _neighbors.begin(), _neighbors.end(), source );
883 if ( found_neighbor == std::end( _neighbors ) )
885 _neighbors.push_back( source );
886 _num_import.push_back( import_sizes[i] );
887 _num_export.push_back( 0 );
895 auto n = std::distance( _neighbors.begin(), found_neighbor );
896 _num_import[n] = import_sizes[i];
902 MPI_Barrier( this->
comm() );
905 return counts_and_ids.second;
936 template <
class RankViewType>
937 Kokkos::View<size_type*, memory_space>
942 element_export_ranks );
984 template <
class ExecutionSpace,
class RankViewType,
class IdViewType>
986 const RankViewType& element_import_ranks,
987 const IdViewType& element_import_ids,
988 const std::vector<int>& neighbor_ranks )
989 -> std::tuple<Kokkos::View<
typename RankViewType::size_type*,
990 typename RankViewType::memory_space>,
991 Kokkos::View<int*, typename RankViewType::memory_space>,
992 Kokkos::View<int*, typename IdViewType::memory_space>>
996 if ( element_import_ids.size() != element_import_ranks.size() )
997 throw std::runtime_error(
"Export ids and ranks different sizes!" );
1001 std::size_t num_n = _neighbors.size();
1005 MPI_Comm_size(
comm(), &comm_size );
1009 MPI_Comm_rank(
comm(), &my_rank );
1013 const int mpi_tag = 1221;
1016 _num_export.assign( num_n, 0 );
1017 _num_import.assign( num_n, 0 );
1021 auto counts_and_ids = Impl::countSendsAndCreateSteering(
1022 exec_space, element_import_ranks, comm_size,
1023 typename Impl::CountSendsAndCreateSteeringAlgorithm<
1024 ExecutionSpace>::type() );
1027 auto neighbor_counts_host = Kokkos::create_mirror_view_and_copy(
1028 Kokkos::HostSpace(), counts_and_ids.first );
1031 for ( std::size_t n = 0; n < num_n; ++n )
1032 _num_import[n] = neighbor_counts_host( _neighbors[n] );
1037 std::vector<MPI_Request> requests;
1038 requests.reserve( num_n * 2 );
1039 for ( std::size_t n = 0; n < num_n; ++n )
1040 if ( my_rank != _neighbors[n] )
1042 requests.push_back( MPI_Request() );
1043 MPI_Irecv( &_num_export[n], 1, MPI_UNSIGNED_LONG, _neighbors[n],
1044 mpi_tag,
comm(), &( requests.back() ) );
1048 _num_export[n] = _num_import[n];
1052 for ( std::size_t n = 0; n < num_n; ++n )
1053 if ( my_rank != _neighbors[n] )
1055 requests.push_back( MPI_Request() );
1056 MPI_Isend( &_num_import[n], 1, MPI_UNSIGNED_LONG, _neighbors[n],
1057 mpi_tag,
comm(), &( requests.back() ) );
1061 std::vector<MPI_Status> status( requests.size() );
1063 MPI_Waitall( requests.size(), requests.data(), status.data() );
1064 if ( MPI_SUCCESS != ec )
1065 throw std::logic_error(
"Failed MPI Communication" );
1069 std::accumulate( _num_export.begin(), _num_export.end(), 0 );
1071 std::accumulate( _num_import.begin(), _num_import.end(), 0 );
1072 _num_export_element = _total_num_export;
1076 Kokkos::View<int*, memory_space> export_indices(
"export_indices",
1077 _total_num_export );
1078 std::size_t idx = 0;
1079 int num_messages = _total_num_export + element_import_ranks.extent( 0 );
1080 std::vector<MPI_Request> mpi_requests( num_messages );
1081 std::vector<MPI_Status> mpi_statuses( num_messages );
1086 for ( std::size_t i = 0; i < num_n; i++ )
1088 for ( std::size_t j = 0; j < _num_export[i]; j++ )
1090 MPI_Irecv( export_indices.data() + idx, 1, MPI_INT,
1091 _neighbors[i], mpi_tag + 1,
comm(),
1092 &mpi_requests[idx] );
1098 for ( std::size_t i = 0; i < element_import_ranks.extent( 0 ); i++ )
1100 MPI_Isend( element_import_ids.data() + i, 1, MPI_INT,
1101 *( element_import_ranks.data() + i ), mpi_tag + 1,
1102 comm(), &mpi_requests[idx++] );
1106 const int ec1 = MPI_Waitall( num_messages, mpi_requests.data(),
1107 mpi_statuses.data() );
1108 if ( MPI_SUCCESS != ec1 )
1109 throw std::logic_error(
"Failed MPI Communication" );
1114 Kokkos::View<int*, Kokkos::HostSpace> element_export_ranks_h(
1115 "element_export_ranks_h", _total_num_export );
1116 for ( std::size_t i = 0; i < _total_num_export; i++ )
1118 element_export_ranks_h[i] = mpi_statuses[i].MPI_SOURCE;
1120 auto element_export_ranks = Kokkos::create_mirror_view_and_copy(
1123 auto counts_and_ids2 = Impl::countSendsAndCreateSteering(
1124 exec_space, element_export_ranks, comm_size,
1125 typename Impl::CountSendsAndCreateSteeringAlgorithm<
1126 ExecutionSpace>::type() );
1132 return std::tuple{ counts_and_ids2.second, element_export_ranks,
1173 template <
class RankViewType,
class IdViewType>
1175 const IdViewType& element_import_ids,
1176 const std::vector<int>& neighbor_ranks )
1180 element_import_ranks, element_import_ids,
1216 template <
class ExecutionSpace,
class RankViewType,
class IdViewType>
1218 const RankViewType& element_import_ranks,
1219 const IdViewType& element_import_ids )
1220 -> std::tuple<Kokkos::View<
typename RankViewType::size_type*,
1221 typename RankViewType::memory_space>,
1222 Kokkos::View<int*, typename RankViewType::memory_space>,
1223 Kokkos::View<int*, typename IdViewType::memory_space>>
1227 if ( element_import_ids.size() != element_import_ranks.size() )
1228 throw std::runtime_error(
"Export ids and ranks different sizes!" );
1232 MPI_Comm_size(
comm(), &comm_size );
1236 MPI_Comm_rank(
comm(), &rank );
1240 const int mpi_tag = 1221;
1243 Kokkos::View<int*, memory_space> importing_ranks(
"importing_ranks",
1245 Kokkos::deep_copy( importing_ranks, 0 );
1246 Kokkos::parallel_for(
1247 "Cabana::storeImportRanks",
1248 Kokkos::RangePolicy<ExecutionSpace>(
1249 0, element_import_ranks.extent( 0 ) ),
1250 KOKKOS_LAMBDA(
const int i ) {
1251 int import_rank = element_import_ranks( i );
1252 Kokkos::atomic_store( &importing_ranks( import_rank ), 1 );
1255 auto importing_ranks_h = Kokkos::create_mirror_view_and_copy(
1256 Kokkos::HostSpace(), importing_ranks );
1259 Kokkos::View<int*, Kokkos::HostSpace> num_ranks_communicate(
1260 "num_ranks_communicate", comm_size );
1261 MPI_Allreduce( importing_ranks_h.data(), num_ranks_communicate.data(),
1262 comm_size, MPI_INT, MPI_SUM,
comm() );
1266 int num_recvs = num_ranks_communicate( rank );
1267 Kokkos::View<int*, Kokkos::HostSpace> send_counts(
"send_counts",
1269 Kokkos::View<int*, Kokkos::HostSpace> send_to(
"send_to", num_recvs );
1271 std::vector<MPI_Request> mpi_requests( num_recvs );
1272 std::vector<MPI_Status> mpi_statuses( num_recvs );
1275 for (
int i = 0; i < num_recvs; i++ )
1277 MPI_Irecv( &send_counts( i ), 1, MPI_INT, MPI_ANY_SOURCE, mpi_tag,
1278 comm(), &mpi_requests[i] );
1283 auto counts_and_ids = Impl::countSendsAndCreateSteering(
1284 exec_space, element_import_ranks, comm_size,
1285 typename Impl::CountSendsAndCreateSteeringAlgorithm<
1286 ExecutionSpace>::type() );
1289 auto neighbor_counts_host = Kokkos::create_mirror_view_and_copy(
1290 Kokkos::HostSpace(), counts_and_ids.first );
1294 _num_export.clear();
1295 _num_import.clear();
1297 for ( std::size_t i = 0; i < neighbor_counts_host.extent( 0 ); i++ )
1299 if ( neighbor_counts_host( i ) != 0 )
1302 MPI_Send( &neighbor_counts_host( i ), 1, MPI_INT, i, mpi_tag,
1306 _neighbors.push_back( i );
1307 _num_import.push_back( neighbor_counts_host( i ) );
1311 _num_export.assign( _num_import.size(), 0 );
1315 MPI_Waitall( num_recvs, mpi_requests.data(), mpi_statuses.data() );
1316 if ( MPI_SUCCESS != ec0 )
1317 throw std::logic_error(
"Failed MPI Communication" );
1321 _total_num_export = 0;
1322 for (
int i = 0; i < num_recvs; i++ )
1324 send_to( i ) = mpi_statuses[i].MPI_SOURCE;
1325 _total_num_export += send_counts( i );
1330 for (
int r = 0; r < num_recvs; ++r )
1332 int export_to = send_to( r );
1333 if ( export_to > -1 )
1337 auto found_neighbor = std::find( _neighbors.begin(),
1338 _neighbors.end(), export_to );
1342 if ( found_neighbor == std::end( _neighbors ) )
1344 _neighbors.push_back( export_to );
1345 _num_import.push_back( 0 );
1346 _num_export.push_back( send_counts( r ) );
1355 std::distance( _neighbors.begin(), found_neighbor );
1356 _num_export[n] = send_counts( r );
1363 throw std::runtime_error(
1364 "CommunicationPlan::createFromImportsOnly: "
1365 "mpi_statuses[i].MPI_SOURCE returned a value >= -1" );
1370 for ( std::size_t n = 0; n < _neighbors.size(); ++n )
1371 if ( _neighbors[n] == rank )
1373 std::swap( _neighbors[n], _neighbors[0] );
1374 std::swap( _num_export[n], _num_export[0] );
1375 std::swap( _num_import[n], _num_import[0] );
1376 _num_export[0] = _num_import[0];
1381 _total_num_import = element_import_ranks.extent( 0 );
1382 _num_export_element = _total_num_export;
1386 Kokkos::View<int*, memory_space> export_indices(
"export_indices",
1387 _total_num_export );
1388 std::size_t idx = 0;
1389 mpi_requests.clear();
1390 mpi_statuses.clear();
1391 int num_messages = _total_num_export + element_import_ranks.extent( 0 );
1392 mpi_requests.resize( num_messages );
1393 mpi_statuses.resize( num_messages );
1398 for (
int i = 0; i < num_recvs; i++ )
1400 for (
int j = 0; j < send_counts( i ); j++ )
1402 MPI_Irecv( export_indices.data() + idx, 1, MPI_INT,
1403 send_to( i ), mpi_tag + 1,
comm(),
1404 &mpi_requests[idx] );
1410 for ( std::size_t i = 0; i < element_import_ranks.extent( 0 ); i++ )
1412 MPI_Isend( element_import_ids.data() + i, 1, MPI_INT,
1413 *( element_import_ranks.data() + i ), mpi_tag + 1,
1414 comm(), &mpi_requests[idx++] );
1418 const int ec1 = MPI_Waitall( num_messages, mpi_requests.data(),
1419 mpi_statuses.data() );
1420 if ( MPI_SUCCESS != ec1 )
1421 throw std::logic_error(
"Failed MPI Communication" );
1426 Kokkos::View<int*, Kokkos::HostSpace> element_export_ranks_h(
1427 "element_export_ranks_h", _total_num_export );
1428 for ( std::size_t i = 0; i < _total_num_export; i++ )
1430 element_export_ranks_h[i] = mpi_statuses[i].MPI_SOURCE;
1432 auto element_export_ranks = Kokkos::create_mirror_view_and_copy(
1435 auto counts_and_ids2 = Impl::countSendsAndCreateSteering(
1436 exec_space, element_export_ranks, comm_size,
1437 typename Impl::CountSendsAndCreateSteeringAlgorithm<
1438 ExecutionSpace>::type() );
1442 MPI_Barrier( this->
comm() );
1444 return std::tuple{ counts_and_ids2.second, element_export_ranks,
1478 template <
class RankViewType,
class IdViewType>
1480 const RankViewType& element_import_ranks,
1481 const IdViewType& element_import_ids )
1485 element_import_ranks,
1486 element_import_ids );
1503 template <
class PackViewType,
class RankViewType>
1505 const RankViewType& element_export_ranks )
1508 createSteering(
true, neighbor_ids, element_export_ranks,
1509 element_export_ranks );
1531 template <
class PackViewType,
class RankViewType,
class IdViewType>
1533 const RankViewType& element_export_ranks,
1534 const IdViewType& element_export_ids )
1536 createSteering(
false, neighbor_ids, element_export_ranks,
1537 element_export_ids );
1542 template <
class ExecutionSpace,
class PackViewType,
class RankViewType,
1544 void createSteering( ExecutionSpace,
const bool use_iota,
1545 const PackViewType& neighbor_ids,
1546 const RankViewType& element_export_ranks,
1547 const IdViewType& element_export_ids )
1552 ( element_export_ids.size() != element_export_ranks.size() ) )
1553 throw std::runtime_error(
1554 "Cabana::CommunicationPlan::createSteering: Export ids and "
1555 "ranks different sizes!" );
1559 MPI_Comm_size( *_comm_ptr, &comm_size );
1563 int num_n = _neighbors.size();
1564 std::vector<std::size_t> offsets( num_n, 0.0 );
1565 for (
int n = 1; n < num_n; ++n )
1566 offsets[n] = offsets[n - 1] + _num_export[n - 1];
1569 Kokkos::View<std::size_t*, Kokkos::HostSpace> rank_offsets_host(
1570 Kokkos::ViewAllocateWithoutInitializing(
"rank_map" ), comm_size );
1571 for (
int n = 0; n < num_n; ++n )
1572 rank_offsets_host( _neighbors[n] ) = offsets[n];
1573 auto rank_offsets = Kokkos::create_mirror_view_and_copy(
1579 _export_steering = Kokkos::View<std::size_t*, memory_space>(
1580 Kokkos::ViewAllocateWithoutInitializing(
"export_steering" ),
1581 _total_num_export );
1582 auto steer_vec = _export_steering;
1583 Kokkos::parallel_for(
1584 "Cabana::CommunicationPlan::createSteering",
1585 Kokkos::RangePolicy<ExecutionSpace>( 0, _num_export_element ),
1586 KOKKOS_LAMBDA(
const int i ) {
1587 if ( element_export_ranks( i ) >= 0 )
1588 steer_vec( rank_offsets( element_export_ranks( i ) ) +
1589 neighbor_ids( i ) ) =
1590 ( use_iota ) ? i : element_export_ids( i );
1595 template <
class PackViewType,
class RankViewType,
class IdViewType>
1596 void createSteering(
const bool use_iota,
const PackViewType& neighbor_ids,
1597 const RankViewType& element_export_ranks,
1598 const IdViewType& element_export_ids )
1602 element_export_ranks, element_export_ids );
1607 std::shared_ptr<MPI_Comm> _comm_ptr;
1608 std::vector<int> _neighbors;
1609 std::size_t _total_num_export;
1610 std::size_t _total_num_import;
1611 std::vector<std::size_t> _num_export;
1612 std::vector<std::size_t> _num_import;
1613 std::size_t _num_export_element;
1614 Kokkos::View<std::size_t*, memory_space> _export_steering;
1621template <
class AoSoAType>
1643 Kokkos::ViewAllocateWithoutInitializing(
"send_buffer" ), 0 );
1645 Kokkos::ViewAllocateWithoutInitializing(
"recv_buffer" ), 0 );
1672template <
class SliceType>
1685 typename Kokkos::View<data_type**, Kokkos::LayoutRight, memory_space>;
1697 Kokkos::ViewAllocateWithoutInitializing(
"send_buffer" ), 0, 0 );
1699 Kokkos::ViewAllocateWithoutInitializing(
"recv_buffer" ), 0, 0 );
1717 for ( std::size_t d = 2; d <
_particles.viewRank(); ++d )
1735template <
class CommPlanType,
class CommDataType>
1764 const double overallocation = 1.0 )
1809 if ( use_overallocation )
1814 _comm_data.reallocateSend( shrunk_send_size );
1815 _comm_data.reallocateReceive( shrunk_recv_size );
1822 template <
class ExecutionSpace>
1826 void reserveImpl(
const CommPlanType& comm_plan,
1828 const std::size_t total_send,
1829 const std::size_t total_recv,
1830 const double overallocation )
1832 if ( overallocation < 1.0 )
1833 throw std::runtime_error(
"Cabana::CommunicationPlan: "
1834 "Cannot allocate buffers with less space "
1835 "than data to communicate!" );
1838 reserveImpl( comm_plan, particles, total_send, total_recv );
1840 void reserveImpl(
const CommPlanType& comm_plan,
1842 const std::size_t total_send,
1843 const std::size_t total_recv )
1849 auto new_send_size =
static_cast<std::size_t
>(
1851 if ( new_send_size > send_capacity )
1855 auto new_recv_size =
static_cast<std::size_t
>(
1857 if ( new_recv_size > recv_capacity )
1858 _comm_data.reallocateReceive( new_recv_size );
void setData(const particle_data_type &particles)
Update particles to communicate.
Definition Cabana_CommunicationPlan.hpp:1779
auto sendCapacity()
Current allocated send buffer space.
Definition Cabana_CommunicationPlan.hpp:1797
typename plan_type::execution_space execution_space
Kokkos execution space.
Definition Cabana_CommunicationPlan.hpp:1742
void shrinkToFit(const bool use_overallocation=false)
Reduce communication buffers to current send/receive sizes.
Definition Cabana_CommunicationPlan.hpp:1805
auto receiveSize()
Current receive buffer size.
Definition Cabana_CommunicationPlan.hpp:1795
buffer_type getSendBuffer() const
Get the communication send buffer.
Definition Cabana_CommunicationPlan.hpp:1772
particle_data_type getData() const
Get the particles to communicate.
Definition Cabana_CommunicationPlan.hpp:1777
plan_type _comm_plan
Definition Cabana_CommunicationPlan.hpp:1870
std::size_t _recv_size
Definition Cabana_CommunicationPlan.hpp:1878
void apply(ExecutionSpace)
Perform the communication (migrate, gather, scatter).
typename comm_data_type::data_type data_type
Communication data type.
Definition Cabana_CommunicationPlan.hpp:1752
comm_data_type _comm_data
Definition Cabana_CommunicationPlan.hpp:1872
double _overallocation
Definition Cabana_CommunicationPlan.hpp:1874
typename comm_data_type::particle_data_type particle_data_type
Particle data type.
Definition Cabana_CommunicationPlan.hpp:1748
CommDataType comm_data_type
Communication data type.
Definition Cabana_CommunicationPlan.hpp:1746
Kokkos::RangePolicy< execution_space > policy_type
Kokkos execution policy.
Definition Cabana_CommunicationPlan.hpp:1744
typename comm_data_type::buffer_type buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlan.hpp:1754
auto getSliceComponents()
Get the total number of components in the slice.
Definition Cabana_CommunicationPlan.hpp:1867
CommPlanType plan_type
Communication plan type (Halo, Distributor)
Definition Cabana_CommunicationPlan.hpp:1740
CommunicationData(const CommPlanType &comm_plan, const particle_data_type &particles, const double overallocation=1.0)
Definition Cabana_CommunicationPlan.hpp:1762
auto receiveCapacity()
Current allocated receive buffer space.
Definition Cabana_CommunicationPlan.hpp:1799
virtual void apply()=0
Perform the communication (migrate, gather, scatter).
auto sendSize()
Current send buffer size.
Definition Cabana_CommunicationPlan.hpp:1789
typename comm_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlan.hpp:1750
buffer_type getReceiveBuffer() const
Get the communication receive buffer.
Definition Cabana_CommunicationPlan.hpp:1774
std::size_t _send_size
Definition Cabana_CommunicationPlan.hpp:1876
Kokkos::View< size_type *, memory_space > createWithTopology(Export, const RankViewType &element_export_ranks, const std::vector< int > &neighbor_ranks)
Neighbor and export rank creator. Use this when you already know which ranks neighbor each other (i....
Definition Cabana_CommunicationPlan.hpp:730
Kokkos::View< std::size_t *, memory_space > getExportSteering() const
Get the steering vector for the exports.
Definition Cabana_CommunicationPlan.hpp:560
std::size_t exportSize() const
Get the number of export elements.
Definition Cabana_CommunicationPlan.hpp:549
typename memory_space::memory_space::size_type size_type
Size type.
Definition Cabana_CommunicationPlan.hpp:451
auto createWithTopology(Import, const RankViewType &element_import_ranks, const IdViewType &element_import_ids, const std::vector< int > &neighbor_ranks)
Neighbor and import rank creator. Use this when you already know which ranks neighbor each other (i....
Definition Cabana_CommunicationPlan.hpp:1174
Kokkos::View< size_type *, memory_space > createWithoutTopology(ExecutionSpace exec_space, Export, const RankViewType &element_export_ranks)
Export rank creator. Use this when you don't know who you will receiving from - only who you are send...
Definition Cabana_CommunicationPlan.hpp:770
int numNeighbor() const
Get the number of neighbor ranks that this rank will communicate with.
Definition Cabana_CommunicationPlan.hpp:487
Kokkos::View< size_type *, memory_space > createWithTopology(ExecutionSpace exec_space, Export, const RankViewType &element_export_ranks, const std::vector< int > &neighbor_ranks)
Neighbor and export rank creator. Use this when you already know which ranks neighbor each other (i....
Definition Cabana_CommunicationPlan.hpp:608
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlan.hpp:441
void createExportSteering(const PackViewType &neighbor_ids, const RankViewType &element_export_ranks)
Create the export steering vector.
Definition Cabana_CommunicationPlan.hpp:1504
auto createWithoutTopology(Import, const RankViewType &element_import_ranks, const IdViewType &element_import_ids)
Import rank creator. Use this when you don't know who you will be receiving from - only who you are i...
Definition Cabana_CommunicationPlan.hpp:1479
std::size_t totalNumExport() const
Get the total number of exports this rank will do.
Definition Cabana_CommunicationPlan.hpp:517
MPI_Comm comm() const
Get the MPI communicator.
Definition Cabana_CommunicationPlan.hpp:480
auto createWithTopology(ExecutionSpace exec_space, Import, const RankViewType &element_import_ranks, const IdViewType &element_import_ids, const std::vector< int > &neighbor_ranks) -> std::tuple< Kokkos::View< typename RankViewType::size_type *, typename RankViewType::memory_space >, Kokkos::View< int *, typename RankViewType::memory_space >, Kokkos::View< int *, typename IdViewType::memory_space > >
Neighbor and import rank creator. Use this when you already know which ranks neighbor each other (i....
Definition Cabana_CommunicationPlan.hpp:985
std::size_t numExport(const int neighbor) const
Get the number of elements this rank will export to a given neighbor.
Definition Cabana_CommunicationPlan.hpp:507
std::size_t numImport(const int neighbor) const
Get the number of elements this rank will import from a given neighbor.
Definition Cabana_CommunicationPlan.hpp:527
std::size_t totalNumImport() const
Get the total number of imports this rank will do.
Definition Cabana_CommunicationPlan.hpp:537
int neighborRank(const int neighbor) const
Given a local neighbor id get its rank in the MPI communicator.
Definition Cabana_CommunicationPlan.hpp:494
void createExportSteering(const PackViewType &neighbor_ids, const RankViewType &element_export_ranks, const IdViewType &element_export_ids)
Create the export steering vector.
Definition Cabana_CommunicationPlan.hpp:1532
auto createWithoutTopology(ExecutionSpace exec_space, Import, const RankViewType &element_import_ranks, const IdViewType &element_import_ids) -> std::tuple< Kokkos::View< typename RankViewType::size_type *, typename RankViewType::memory_space >, Kokkos::View< int *, typename RankViewType::memory_space >, Kokkos::View< int *, typename IdViewType::memory_space > >
Import rank creator. Use this when you don't know who you will be receiving from - only who you are i...
Definition Cabana_CommunicationPlan.hpp:1217
Kokkos::View< size_type *, memory_space > createWithoutTopology(Export, const RankViewType &element_export_ranks)
Export rank creator. Use this when you don't know who you will receiving from - only who you are send...
Definition Cabana_CommunicationPlan.hpp:938
CommunicationPlan(MPI_Comm comm)
Constructor.
Definition Cabana_CommunicationPlan.hpp:458
typename memory_space::execution_space execution_space
Default execution space.
Definition Cabana_CommunicationPlan.hpp:445
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
std::vector< int > getUniqueTopology(MPI_Comm comm, std::vector< int > topology)
Return unique neighbor ranks, with the current rank first.
Definition Cabana_CommunicationPlan.hpp:388
buffer_type _send_buffer
Send buffer.
Definition Cabana_CommunicationPlan.hpp:1660
void reallocateSend(const std::size_t num_send)
Resize the send buffer.
Definition Cabana_CommunicationPlan.hpp:1649
typename particle_data_type::tuple_type data_type
Communication data type.
Definition Cabana_CommunicationPlan.hpp:1631
AoSoAType particle_data_type
Particle data type.
Definition Cabana_CommunicationPlan.hpp:1627
buffer_type _recv_buffer
Receive buffer.
Definition Cabana_CommunicationPlan.hpp:1662
typename particle_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlan.hpp:1629
particle_data_type _particles
Particle AoSoA.
Definition Cabana_CommunicationPlan.hpp:1664
CommunicationDataAoSoA(particle_data_type particles)
Definition Cabana_CommunicationPlan.hpp:1639
typename Kokkos::View< data_type *, memory_space > buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlan.hpp:1633
std::size_t _num_comp
Slice components.
Definition Cabana_CommunicationPlan.hpp:1666
void reallocateReceive(const std::size_t num_recv)
Resize the receive buffer.
Definition Cabana_CommunicationPlan.hpp:1654
void setSliceComponents()
Get the total number of components in the slice.
Definition Cabana_CommunicationPlan.hpp:1714
void reallocateSend(const std::size_t num_send)
Resize the send buffer.
Definition Cabana_CommunicationPlan.hpp:1703
buffer_type _send_buffer
Send buffer.
Definition Cabana_CommunicationPlan.hpp:1722
buffer_type _recv_buffer
Receive buffer.
Definition Cabana_CommunicationPlan.hpp:1724
void reallocateReceive(const std::size_t num_recv)
Resize the receive buffer.
Definition Cabana_CommunicationPlan.hpp:1708
typename Kokkos::View< data_type **, Kokkos::LayoutRight, memory_space > buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlan.hpp:1684
typename particle_data_type::value_type data_type
Communication data type.
Definition Cabana_CommunicationPlan.hpp:1682
typename particle_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlan.hpp:1680
SliceType particle_data_type
Particle data type.
Definition Cabana_CommunicationPlan.hpp:1678
std::size_t _num_comp
Slice components.
Definition Cabana_CommunicationPlan.hpp:1728
particle_data_type _particles
Particle slice.
Definition Cabana_CommunicationPlan.hpp:1726
CommunicationDataSlice(particle_data_type particles)
Definition Cabana_CommunicationPlan.hpp:1691
Export-based tag - default.
Definition Cabana_CommunicationPlan.hpp:42
Import-based tag.
Definition Cabana_CommunicationPlan.hpp:49
Definition Cabana_Types.hpp:88
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:868