Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_CommunicationPlanBase.hpp
Go to the documentation of this file.
1/****************************************************************************
2 * Copyright (c) 2018-2023 by the Cabana authors *
3 * All rights reserved. *
4 * *
5 * This file is part of the Cabana library. Cabana is distributed under a *
6 * BSD 3-clause license. For the licensing terms see the LICENSE file in *
7 * the top-level directory. *
8 * *
9 * SPDX-License-Identifier: BSD-3-Clause *
10 ****************************************************************************/
11
16#ifndef CABANA_COMMUNICATIONPLANBASE_HPP
17#define CABANA_COMMUNICATIONPLANBASE_HPP
18
19#include <Cabana_Core_Config.hpp>
20#include <Cabana_Tags.hpp>
21#include <Cabana_Utils.hpp>
22
23#include <Kokkos_Core.hpp>
24#include <Kokkos_ScatterView.hpp>
25
26#include <mpi.h>
27
28#include <algorithm>
29#include <exception>
30#include <memory>
31#include <numeric>
32#include <type_traits>
33#include <vector>
34
35namespace Cabana
36{
37//---------------------------------------------------------------------------//
38
39namespace Impl
40{
42//---------------------------------------------------------------------------//
43// Count sends and create steering algorithm tags.
44struct CountSendsAndCreateSteeringDuplicated
45{
46};
47struct CountSendsAndCreateSteeringAtomic
48{
49};
50
51//---------------------------------------------------------------------------//
52// Count sends and create steering algorithm selector.
53template <class ExecutionSpace>
54struct CountSendsAndCreateSteeringAlgorithm;
55
56// CUDA and HIP use atomics.
57#ifdef KOKKOS_ENABLE_CUDA
58template <>
59struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Cuda>
60{
61 using type = CountSendsAndCreateSteeringAtomic;
62};
63#endif // end KOKKOS_ENABLE_CUDA
64#ifdef KOKKOS_ENABLE_HIP
65template <>
66struct CountSendsAndCreateSteeringAlgorithm<Kokkos::HIP>
67{
68 using type = CountSendsAndCreateSteeringAtomic;
69};
70#endif // end KOKKOS_ENABLE_HIP
71#ifdef KOKKOS_ENABLE_SYCL
72template <>
73struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Experimental::SYCL>
74{
75 using type = CountSendsAndCreateSteeringAtomic;
76};
77#endif // end KOKKOS_ENABLE_SYCL
78#ifdef KOKKOS_ENABLE_OPENMPTARGET
79template <>
80struct CountSendsAndCreateSteeringAlgorithm<Kokkos::Experimental::OpenMPTarget>
81{
82 using type = CountSendsAndCreateSteeringAtomic;
83};
84#endif // end KOKKOS_ENABLE_OPENMPTARGET
85
86// The default is to use duplication.
87template <class ExecutionSpace>
88struct CountSendsAndCreateSteeringAlgorithm
89{
90 using type = CountSendsAndCreateSteeringDuplicated;
91};
92
93//---------------------------------------------------------------------------//
94// Count sends and generate the steering vector. Atomic version.
95template <class ExecutionSpace, class ExportRankView>
96auto countSendsAndCreateSteering( ExecutionSpace,
97 const ExportRankView element_export_ranks,
98 const int comm_size,
99 CountSendsAndCreateSteeringAtomic )
100 -> std::pair<Kokkos::View<int*, typename ExportRankView::memory_space>,
101 Kokkos::View<typename ExportRankView::size_type*,
102 typename ExportRankView::memory_space>>
103{
104 using memory_space = typename ExportRankView::memory_space;
105 using size_type = typename ExportRankView::size_type;
106
107 // Create views.
108 Kokkos::View<int*, memory_space> neighbor_counts( "neighbor_counts",
109 comm_size );
110 Kokkos::View<size_type*, memory_space> neighbor_ids(
111 Kokkos::ViewAllocateWithoutInitializing( "neighbor_ids" ),
112 element_export_ranks.size() );
113
114 // Count the sends and create the steering vector.
115
116 // For smaller values of comm_size, use the optimized scratch memory path
117 // Value of 64 is arbitrary, should be at least 27 to cover 3-d halos?
118 if ( comm_size <= 64 )
119 {
120 constexpr int team_size = 256;
121 Kokkos::TeamPolicy<ExecutionSpace> team_policy(
122 ( element_export_ranks.size() + team_size - 1 ) / team_size,
123 team_size );
124 team_policy = team_policy.set_scratch_size(
125 0,
126 Kokkos::PerTeam( sizeof( int ) * ( team_size + 2 * comm_size ) ) );
127 Kokkos::parallel_for(
128 "Cabana::CommunicationPlan::countSendsAndCreateSteeringShared",
129 team_policy,
130 KOKKOS_LAMBDA(
131 const typename Kokkos::TeamPolicy<ExecutionSpace>::member_type&
132 team ) {
133 // NOTE: `get_shmem` returns shared memory pointers *aligned to
134 // 8 bytes*, so if `comm_size` is odd we can get erroneously
135 // padded offsets if we call `get_shmem` separately for each
136 // shared memory intermediary. Acquiring all the needed scratch
137 // memory at once then computing pointer offsets by hand avoids
138 // this issue.
139 int* scratch = (int*)team.team_shmem().get_shmem(
140 ( team.team_size() + 2 * comm_size ) * sizeof( int ), 0 );
141
142 // local neighbor_ids, gives the local offset relative to
143 // calculated global offset. Size team.team_size() * sizeof(int)
144 int* local_neighbor_ids = scratch;
145 // local histogram, `comm_size` in size
146 int* histo = local_neighbor_ids + team.team_size();
147 // offset into global array, `comm_size` in size
148 int* global_offset = histo + comm_size;
149 // overall element `tid`
150 const auto tid =
151 team.team_rank() + team.league_rank() * team.team_size();
152 // local element
153 const int local_id = team.team_rank();
154 // total number of elements, for convenience
155 const int num_elements = element_export_ranks.size();
156 // my element export rank
157 const int my_element_export_rank =
158 ( tid < num_elements ? element_export_ranks( tid ) : -1 );
159
160 // cannot outright terminate early b/c threads share work
161 // if (tid >= num_elements) return;
162 const bool in_bounds =
163 tid < num_elements && my_element_export_rank >= 0;
164
165 Kokkos::parallel_for(
166 Kokkos::TeamThreadRange( team, comm_size ),
167 [&]( const int i ) { histo[i] = 0; } );
168
169 // synchronize zeroing
170 team.team_barrier();
171
172 // build local histogram, need to encode num_elements check here
173 if ( in_bounds )
174 {
175 // shared memory atomic add, accumulate into local offset
176 local_neighbor_ids[local_id] = Kokkos::atomic_fetch_add(
177 &histo[my_element_export_rank], 1 );
178 }
179
180 // synchronize local histogram build
181 team.team_barrier();
182
183 // reserve space in global array via a loop over neighbor counts
184 Kokkos::parallel_for(
185 Kokkos::TeamThreadRange( team, comm_size ),
186 [&]( const int i )
187 {
188 // global memory atomic add, reserves space
189 global_offset[i] = Kokkos::atomic_fetch_add(
190 &neighbor_counts( i ), histo[i] );
191 } );
192
193 // synchronize block-stride loop
194 team.team_barrier();
195
196 // and now store to my location
197 if ( in_bounds )
198 {
199 neighbor_ids( tid ) =
200 global_offset[my_element_export_rank] +
201 local_neighbor_ids[local_id];
202 }
203 } );
204 }
205 else
206 {
207 // For larger numbers of export ranks (for ex, migration) we use the
208 // global memory version, though this is a point of future optimization
209
210 Kokkos::parallel_for(
211 "Cabana::CommunicationPlan::countSendsAndCreateSteering",
212 Kokkos::RangePolicy<ExecutionSpace>( 0,
213 element_export_ranks.size() ),
214 KOKKOS_LAMBDA( const size_type i ) {
215 if ( element_export_ranks( i ) >= 0 )
216 neighbor_ids( i ) = Kokkos::atomic_fetch_add(
217 &neighbor_counts( element_export_ranks( i ) ), 1 );
218 } );
219 }
220 Kokkos::fence();
221
222 // Return the counts and ids.
223 return std::make_pair( neighbor_counts, neighbor_ids );
224}
225
226//---------------------------------------------------------------------------//
227// Count sends and generate the steering vector. Duplicated version.
228template <class ExecutionSpace, class ExportRankView>
229auto countSendsAndCreateSteering( ExecutionSpace,
230 const ExportRankView element_export_ranks,
231 const int comm_size,
232 CountSendsAndCreateSteeringDuplicated )
233 -> std::pair<Kokkos::View<int*, typename ExportRankView::memory_space>,
234 Kokkos::View<typename ExportRankView::size_type*,
235 typename ExportRankView::memory_space>>
236{
237 using memory_space = typename ExportRankView::memory_space;
238 using size_type = typename ExportRankView::size_type;
239
240 // Create a unique thread token.
241 Kokkos::Experimental::UniqueToken<
242 ExecutionSpace, Kokkos::Experimental::UniqueTokenScope::Global>
243 unique_token;
244
245 // Create views.
246 Kokkos::View<int*, memory_space> neighbor_counts(
247 Kokkos::ViewAllocateWithoutInitializing( "neighbor_counts" ),
248 comm_size );
249 Kokkos::View<size_type*, memory_space> neighbor_ids(
250 Kokkos::ViewAllocateWithoutInitializing( "neighbor_ids" ),
251 element_export_ranks.size() );
252 Kokkos::View<int**, memory_space> neighbor_counts_dup(
253 "neighbor_counts", unique_token.size(), comm_size );
254 Kokkos::View<size_type**, memory_space> neighbor_ids_dup(
255 "neighbor_ids", unique_token.size(), element_export_ranks.size() );
256
257 // Compute initial duplicated sends and steering.
258 Kokkos::parallel_for(
259 "Cabana::CommunicationPlan::intialCount",
260 Kokkos::RangePolicy<ExecutionSpace>( 0, element_export_ranks.size() ),
261 KOKKOS_LAMBDA( const size_type i ) {
262 if ( element_export_ranks( i ) >= 0 )
263 {
264 // Get the thread id.
265 auto thread_id = unique_token.acquire();
266
267 // Do the duplicated fetch-add. If this is a valid element id
268 // increment the send count for this rank. Add the incremented
269 // count as the thread-local neighbor id. This is too big by
270 // one (because we use the prefix increment operator) but we
271 // want a non-zero value so we can later find which thread
272 // this element was located on because we are always
273 // guaranteed a non-zero value. We will subtract this value
274 // later.
275 neighbor_ids_dup( thread_id, i ) = ++neighbor_counts_dup(
276 thread_id, element_export_ranks( i ) );
277
278 // Release the thread id.
279 unique_token.release( thread_id );
280 }
281 } );
282 Kokkos::fence();
283
284 // Team policy
285 using team_policy =
286 Kokkos::TeamPolicy<ExecutionSpace, Kokkos::Schedule<Kokkos::Dynamic>>;
287 using index_type = typename team_policy::index_type;
288
289 // Compute the send counts for each neighbor rank by reducing across
290 // the thread duplicates.
291 Kokkos::parallel_for(
292 "Cabana::CommunicationPlan::finalCount",
293 team_policy( neighbor_counts.extent( 0 ), Kokkos::AUTO ),
294 KOKKOS_LAMBDA( const typename team_policy::member_type& team ) {
295 // Get the element id.
296 auto i = team.league_rank();
297
298 // Add the thread results.
299 int thread_counts = 0;
300 Kokkos::parallel_reduce(
301 Kokkos::TeamThreadRange( team,
302 neighbor_counts_dup.extent( 0 ) ),
303 [&]( const index_type thread_id, int& result )
304 { result += neighbor_counts_dup( thread_id, i ); },
305 thread_counts );
306 neighbor_counts( i ) = thread_counts;
307 } );
308 Kokkos::fence();
309
310 // Compute the location of each export element in the send buffer of
311 // its destination rank.
312 Kokkos::parallel_for(
313 "Cabana::CommunicationPlan::createSteering",
314 team_policy( element_export_ranks.size(), Kokkos::AUTO ),
315 KOKKOS_LAMBDA( const typename team_policy::member_type& team ) {
316 // Get the element id.
317 auto i = team.league_rank();
318
319 // Only operate on valid elements
320 if ( element_export_ranks( i ) >= 0 )
321 {
322 // Compute the thread id in which we located the element
323 // during the count phase. Only the thread in which we
324 // located the element will contribute to the reduction.
325 index_type dup_thread = 0;
326 Kokkos::parallel_reduce(
327 Kokkos::TeamThreadRange( team,
328 neighbor_ids_dup.extent( 0 ) ),
329 [&]( const index_type thread_id, index_type& result )
330 {
331 if ( neighbor_ids_dup( thread_id, i ) > 0 )
332 result += thread_id;
333 },
334 dup_thread );
335
336 // Compute the offset of this element in the steering
337 // vector for its destination rank. Loop through the
338 // threads up to the thread that found this element in the
339 // count stage. All thread counts prior to that thread
340 // will contribute to the offset.
341 size_type thread_offset = 0;
342 Kokkos::parallel_reduce(
343 Kokkos::TeamThreadRange( team, dup_thread ),
344 [&]( const index_type thread_id, size_type& result ) {
345 result += neighbor_counts_dup(
346 thread_id, element_export_ranks( i ) );
347 },
348 thread_offset );
349
350 // Add the thread-local value to the offset where we subtract
351 // the 1 that we added artificially when we were first
352 // counting.
353 neighbor_ids( i ) =
354 thread_offset + neighbor_ids_dup( dup_thread, i ) - 1;
355 }
356 } );
357 Kokkos::fence();
358
359 // Return the counts and ids.
360 return std::make_pair( neighbor_counts, neighbor_ids );
361}
362
363//---------------------------------------------------------------------------//
365} // end namespace Impl
366
367//---------------------------------------------------------------------------//
374inline std::vector<int> getUniqueTopology( MPI_Comm comm,
375 std::vector<int> topology )
376{
377 auto remove_end = std::remove( topology.begin(), topology.end(), -1 );
378 std::sort( topology.begin(), remove_end );
379 auto unique_end = std::unique( topology.begin(), remove_end );
380 topology.resize( std::distance( topology.begin(), unique_end ) );
381
382 // Put this rank first.
383 int my_rank = -1;
384 MPI_Comm_rank( comm, &my_rank );
385 for ( auto& n : topology )
386 {
387 if ( n == my_rank )
388 {
389 std::swap( n, topology[0] );
390 break;
391 }
392 }
393 return topology;
394}
395
396//---------------------------------------------------------------------------//
422template <class MemorySpace>
424{
425 public:
427 using memory_space = MemorySpace;
428 static_assert( Kokkos::is_memory_space<MemorySpace>() );
429
431 using execution_space = typename memory_space::execution_space;
432
434 using size_type = typename memory_space::memory_space::size_type;
435
436 protected:
443 {
444 _comm_ptr.reset(
445 // Duplicate the communicator and store in a std::shared_ptr so that
446 // all copies point to the same object
447 [comm]()
448 {
449 auto p = std::make_unique<MPI_Comm>();
450 MPI_Comm_dup( comm, p.get() );
451 return p.release();
452 }(),
453 // Custom deleter to mark the communicator for deallocation
454 []( MPI_Comm* p )
455 {
456 MPI_Comm_free( p );
457 delete p;
458 } );
459 }
460
461 public:
465 MPI_Comm comm() const { return *_comm_ptr; }
466
472 int numNeighbor() const { return _neighbors.size(); }
473
479 int neighborRank( const int neighbor ) const
480 {
481 return _neighbors[neighbor];
482 }
483
492 std::size_t numExport( const int neighbor ) const
493 {
494 return _num_export[neighbor];
495 }
496
502 std::size_t totalNumExport() const { return _total_num_export; }
503
512 std::size_t numImport( const int neighbor ) const
513 {
514 return _num_import[neighbor];
515 }
516
522 std::size_t totalNumImport() const { return _total_num_import; }
523
534 std::size_t exportSize() const { return _num_export_element; }
535
545 Kokkos::View<std::size_t*, memory_space> getExportSteering() const
546 {
547 return _export_steering;
548 }
549
550 // The functions in the public block below would normally be protected but
551 // we make them public to allow using private class data in CUDA kernels
552 // with lambda functions.
553 public:
568 template <class PackViewType, class RankViewType>
569 void createExportSteering( const PackViewType& neighbor_ids,
570 const RankViewType& element_export_ranks )
571 {
572 // passing in element_export_ranks here as a dummy argument.
573 createSteering( true, neighbor_ids, element_export_ranks,
574 element_export_ranks );
575 }
576
596 template <class PackViewType, class RankViewType, class IdViewType>
597 void createExportSteering( const PackViewType& neighbor_ids,
598 const RankViewType& element_export_ranks,
599 const IdViewType& element_export_ids )
600 {
601 createSteering( false, neighbor_ids, element_export_ranks,
602 element_export_ids );
603 }
604
606 // Create the export steering vector.
607 template <class ExecutionSpace, class PackViewType, class RankViewType,
608 class IdViewType>
609 void createSteering( ExecutionSpace, const bool use_iota,
610 const PackViewType& neighbor_ids,
611 const RankViewType& element_export_ranks,
612 const IdViewType& element_export_ids )
613 {
615
616 if ( !use_iota &&
617 ( element_export_ids.size() != element_export_ranks.size() ) )
618 throw std::runtime_error(
619 "Cabana::CommunicationPlan::createSteering: Export ids and "
620 "ranks different sizes!" );
621
622 // Get the size of this communicator.
623 int comm_size = -1;
624 MPI_Comm_size( *_comm_ptr, &comm_size );
625
626 // Calculate the steering offsets via exclusive prefix sum for the
627 // exports.
628 int num_n = _neighbors.size();
629 std::vector<std::size_t> offsets( num_n, 0.0 );
630 for ( int n = 1; n < num_n; ++n )
631 offsets[n] = offsets[n - 1] + _num_export[n - 1];
632
633 // Map the offsets to the device.
634 Kokkos::View<std::size_t*, Kokkos::HostSpace> rank_offsets_host(
635 Kokkos::ViewAllocateWithoutInitializing( "rank_map" ), comm_size );
636 for ( int n = 0; n < num_n; ++n )
637 rank_offsets_host( _neighbors[n] ) = offsets[n];
638 auto rank_offsets = Kokkos::create_mirror_view_and_copy(
639 memory_space(), rank_offsets_host );
640
641 // Create the export steering vector for writing local elements into
642 // the send buffer. Note we create a local, shallow copy - this is a
643 // CUDA workaround for handling class private data.
644 _export_steering = Kokkos::View<std::size_t*, memory_space>(
645 Kokkos::ViewAllocateWithoutInitializing( "export_steering" ),
647 auto steer_vec = _export_steering;
648 Kokkos::parallel_for(
649 "Cabana::CommunicationPlan::createSteering",
650 Kokkos::RangePolicy<ExecutionSpace>( 0, _num_export_element ),
651 KOKKOS_LAMBDA( const int i ) {
652 if ( element_export_ranks( i ) >= 0 )
653 steer_vec( rank_offsets( element_export_ranks( i ) ) +
654 neighbor_ids( i ) ) =
655 ( use_iota ) ? i : element_export_ids( i );
656 } );
657 Kokkos::fence();
658 }
659
660 template <class PackViewType, class RankViewType, class IdViewType>
661 void createSteering( const bool use_iota, const PackViewType& neighbor_ids,
662 const RankViewType& element_export_ranks,
663 const IdViewType& element_export_ids )
664 {
665 // Use the default execution space.
666 createSteering( execution_space{}, use_iota, neighbor_ids,
667 element_export_ranks, element_export_ids );
668 }
670
671 protected:
673 std::shared_ptr<MPI_Comm> _comm_ptr;
675 std::vector<int> _neighbors;
677 std::size_t _total_num_export;
679 std::size_t _total_num_import;
681 std::vector<std::size_t> _num_export;
683 std::vector<std::size_t> _num_import;
689 Kokkos::View<std::size_t*, memory_space> _export_steering;
690};
691
692//---------------------------------------------------------------------------//
696template <class AoSoAType>
698{
699 static_assert( is_aosoa<AoSoAType>::value, "" );
700
702 using particle_data_type = AoSoAType;
704 using memory_space = typename particle_data_type::memory_space;
706 using data_type = typename particle_data_type::tuple_type;
708 using buffer_type = typename Kokkos::View<data_type*, memory_space>;
709
715 : _particles( particles )
716 {
718 Kokkos::ViewAllocateWithoutInitializing( "send_buffer" ), 0 );
720 Kokkos::ViewAllocateWithoutInitializing( "recv_buffer" ), 0 );
721 }
722
724 void reallocateSend( const std::size_t num_send )
725 {
726 Kokkos::realloc( _send_buffer, num_send );
727 }
728
729 void reallocateReceive( const std::size_t num_recv )
730 {
731 Kokkos::realloc( _recv_buffer, num_recv );
732 }
733
741 std::size_t _num_comp = 0;
742};
743
747template <class SliceType>
749{
750 static_assert( is_slice<SliceType>::value, "" );
751
753 using particle_data_type = SliceType;
755 using memory_space = typename particle_data_type::memory_space;
757 using data_type = typename particle_data_type::value_type;
760 typename Kokkos::View<data_type**, Kokkos::LayoutRight, memory_space>;
761
767 : _particles( particles )
768 {
770
772 Kokkos::ViewAllocateWithoutInitializing( "send_buffer" ), 0, 0 );
774 Kokkos::ViewAllocateWithoutInitializing( "recv_buffer" ), 0, 0 );
775 }
776
778 void reallocateSend( const std::size_t num_send )
779 {
780 Kokkos::realloc( _send_buffer, num_send, _num_comp );
781 }
782
783 void reallocateReceive( const std::size_t num_recv )
784 {
785 Kokkos::realloc( _recv_buffer, num_recv, _num_comp );
786 }
787
790 {
791 _num_comp = 1;
792 for ( std::size_t d = 2; d < _particles.viewRank(); ++d )
793 _num_comp *= _particles.extent( d );
794 }
795
803 std::size_t _num_comp;
804};
805//---------------------------------------------------------------------------//
806
810template <class CommPlanType, class CommDataType>
812{
813 public:
815 using plan_type = CommPlanType;
817 using execution_space = typename plan_type::execution_space;
819 using policy_type = Kokkos::RangePolicy<execution_space>;
821 using comm_data_type = CommDataType;
823 using particle_data_type = typename comm_data_type::particle_data_type;
825 using memory_space = typename comm_data_type::memory_space;
827 using data_type = typename comm_data_type::data_type;
829 using buffer_type = typename comm_data_type::buffer_type;
830
831 protected:
838 CommunicationDataBase( const CommPlanType& comm_plan,
839 const particle_data_type& particles,
840 const double overallocation = 1.0 )
841 : _comm_plan( comm_plan )
842 , _comm_data( CommDataType( particles ) )
843 , _overallocation( overallocation )
844 {
845 }
846
847 public:
849 buffer_type getSendBuffer() const { return _comm_data._send_buffer; }
851 buffer_type getReceiveBuffer() const { return _comm_data._recv_buffer; }
852
854 particle_data_type getData() const { return _comm_data._particles; }
856 void setData( const particle_data_type& particles )
857 {
858 _comm_data._particles = particles;
859 }
860
866 auto sendSize() { return _send_size; }
872 auto receiveSize() { return _recv_size; }
874 auto sendCapacity() { return _comm_data._send_buffer.extent( 0 ); }
876 auto receiveCapacity() { return _comm_data._recv_buffer.extent( 0 ); }
882 void shrinkToFit( const bool use_overallocation = false )
883 {
884 auto shrunk_send_size = _send_size;
885 auto shrunk_recv_size = _recv_size;
886 if ( use_overallocation )
887 {
888 shrunk_send_size *= _overallocation;
889 shrunk_recv_size *= _overallocation;
890 }
891 _comm_data.reallocateSend( shrunk_send_size );
892 _comm_data.reallocateReceive( shrunk_recv_size );
893 }
894
896 virtual void apply() = 0;
897
899 template <class ExecutionSpace>
900 void apply( ExecutionSpace );
901
903 void reserveImpl( const CommPlanType& comm_plan,
904 const particle_data_type particles,
905 const std::size_t total_send,
906 const std::size_t total_recv,
907 const double overallocation )
908 {
909 if ( overallocation < 1.0 )
910 throw std::runtime_error( "Cabana::CommunicationPlan: "
911 "Cannot allocate buffers with less space "
912 "than data to communicate!" );
913 _overallocation = overallocation;
914
915 reserveImpl( comm_plan, particles, total_send, total_recv );
916 }
917 void reserveImpl( const CommPlanType& comm_plan,
918 const particle_data_type particles,
919 const std::size_t total_send,
920 const std::size_t total_recv )
921 {
922 _comm_plan = comm_plan;
923 setData( particles );
924
925 auto send_capacity = sendCapacity();
926 auto new_send_size = static_cast<std::size_t>(
927 static_cast<double>( total_send ) * _overallocation );
928 if ( new_send_size > send_capacity )
929 _comm_data.reallocateSend( new_send_size );
930
931 auto recv_capacity = receiveCapacity();
932 auto new_recv_size = static_cast<std::size_t>(
933 static_cast<double>( total_recv ) * _overallocation );
934 if ( new_recv_size > recv_capacity )
935 _comm_data.reallocateReceive( new_recv_size );
936
937 _send_size = total_send;
938 _recv_size = total_recv;
939 }
941
942 protected:
944 auto getSliceComponents() { return _comm_data._num_comp; };
945
953 std::size_t _send_size;
955 std::size_t _recv_size;
956};
957
958// Forward declaration of the primary CommunicationPlan template.
959template <class MemorySpace, class CommSpaceType = Mpi>
961
962// Forward declaration of the primary CommunicationData template.
963template <class CommPlanType, class CommDataType, class CommSpaceType = Mpi>
965
966} // namespace Cabana
967
968// Include communication backends from what is enabled in CMake.
969#ifdef Cabana_ENABLE_MPI
971#endif // Enable MPI
972
973#endif // end CABANA_COMMUNICATIONPLANBASE_HPP
Multi-node communication patterns. Uses vanilla MPI as the communication backend.
Type tags used in Cabana.
Cabana utilities.
auto sendSize()
Current send buffer size.
Definition Cabana_CommunicationPlanBase.hpp:866
std::size_t _send_size
Send sizes.
Definition Cabana_CommunicationPlanBase.hpp:953
Kokkos::RangePolicy< execution_space > policy_type
Kokkos execution policy.
Definition Cabana_CommunicationPlanBase.hpp:819
auto receiveSize()
Current receive buffer size.
Definition Cabana_CommunicationPlanBase.hpp:872
typename comm_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlanBase.hpp:825
auto receiveCapacity()
Current allocated receive buffer space.
Definition Cabana_CommunicationPlanBase.hpp:876
comm_data_type _comm_data
Communication plan.
Definition Cabana_CommunicationPlanBase.hpp:949
void setData(const particle_data_type &particles)
Update particles to communicate.
Definition Cabana_CommunicationPlanBase.hpp:856
plan_type _comm_plan
Communication plan.
Definition Cabana_CommunicationPlanBase.hpp:947
particle_data_type getData() const
Get the particles to communicate.
Definition Cabana_CommunicationPlanBase.hpp:854
typename comm_data_type::data_type data_type
Communication data type.
Definition Cabana_CommunicationPlanBase.hpp:827
CommPlanType plan_type
Communication plan type (Halo, Distributor)
Definition Cabana_CommunicationPlanBase.hpp:815
buffer_type getSendBuffer() const
Get the communication send buffer.
Definition Cabana_CommunicationPlanBase.hpp:849
CommDataType comm_data_type
Communication data type.
Definition Cabana_CommunicationPlanBase.hpp:821
typename plan_type::execution_space execution_space
Kokkos execution space.
Definition Cabana_CommunicationPlanBase.hpp:817
typename comm_data_type::particle_data_type particle_data_type
Particle data type.
Definition Cabana_CommunicationPlanBase.hpp:823
void apply(ExecutionSpace)
Perform the communication (migrate, gather, scatter).
double _overallocation
Overallocation factor.
Definition Cabana_CommunicationPlanBase.hpp:951
CommunicationDataBase(const CommPlanType &comm_plan, const particle_data_type &particles, const double overallocation=1.0)
Definition Cabana_CommunicationPlanBase.hpp:838
void shrinkToFit(const bool use_overallocation=false)
Reduce communication buffers to current send/receive sizes.
Definition Cabana_CommunicationPlanBase.hpp:882
typename comm_data_type::buffer_type buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlanBase.hpp:829
auto sendCapacity()
Current allocated send buffer space.
Definition Cabana_CommunicationPlanBase.hpp:874
std::size_t _recv_size
Receive sizes.
Definition Cabana_CommunicationPlanBase.hpp:955
virtual void apply()=0
Perform the communication (migrate, gather, scatter).
buffer_type getReceiveBuffer() const
Get the communication receive buffer.
Definition Cabana_CommunicationPlanBase.hpp:851
auto getSliceComponents()
Get the total number of components in the slice.
Definition Cabana_CommunicationPlanBase.hpp:944
Definition Cabana_CommunicationPlanBase.hpp:964
std::size_t exportSize() const
Get the number of export elements.
Definition Cabana_CommunicationPlanBase.hpp:534
std::size_t _total_num_export
Number of elements exported.
Definition Cabana_CommunicationPlanBase.hpp:677
std::vector< std::size_t > _num_export
Number of elements exported to each neighbor.
Definition Cabana_CommunicationPlanBase.hpp:681
Kokkos::View< std::size_t *, memory_space > _export_steering
Export steering vector.
Definition Cabana_CommunicationPlanBase.hpp:689
CommunicationPlanBase(MPI_Comm comm)
Constructor.
Definition Cabana_CommunicationPlanBase.hpp:442
int neighborRank(const int neighbor) const
Given a local neighbor id get its rank in the MPI communicator.
Definition Cabana_CommunicationPlanBase.hpp:479
std::size_t numImport(const int neighbor) const
Get the number of elements this rank will import from a given neighbor.
Definition Cabana_CommunicationPlanBase.hpp:512
std::size_t totalNumExport() const
Get the total number of exports this rank will do.
Definition Cabana_CommunicationPlanBase.hpp:502
std::size_t totalNumImport() const
Get the total number of imports this rank will do.
Definition Cabana_CommunicationPlanBase.hpp:522
std::shared_ptr< MPI_Comm > _comm_ptr
Shared pointer to Mpi communicator.
Definition Cabana_CommunicationPlanBase.hpp:673
void createExportSteering(const PackViewType &neighbor_ids, const RankViewType &element_export_ranks, const IdViewType &element_export_ids)
Create the export steering vector.
Definition Cabana_CommunicationPlanBase.hpp:597
std::size_t _total_num_import
Number of elements imported.
Definition Cabana_CommunicationPlanBase.hpp:679
void createExportSteering(const PackViewType &neighbor_ids, const RankViewType &element_export_ranks)
Create the export steering vector.
Definition Cabana_CommunicationPlanBase.hpp:569
typename memory_space::memory_space::size_type size_type
Size type.
Definition Cabana_CommunicationPlanBase.hpp:434
int numNeighbor() const
Get the number of neighbor ranks that this rank will communicate with.
Definition Cabana_CommunicationPlanBase.hpp:472
std::size_t _num_export_element
Definition Cabana_CommunicationPlanBase.hpp:687
std::vector< std::size_t > _num_import
Number of elements imported from each neighbor.
Definition Cabana_CommunicationPlanBase.hpp:683
std::vector< int > _neighbors
List of Mpi neighbors.
Definition Cabana_CommunicationPlanBase.hpp:675
std::size_t numExport(const int neighbor) const
Get the number of elements this rank will export to a given neighbor.
Definition Cabana_CommunicationPlanBase.hpp:492
Kokkos::View< std::size_t *, memory_space > getExportSteering() const
Get the steering vector for the exports.
Definition Cabana_CommunicationPlanBase.hpp:545
typename memory_space::execution_space execution_space
Default execution space.
Definition Cabana_CommunicationPlanBase.hpp:431
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlanBase.hpp:427
MPI_Comm comm() const
Get the MPI communicator.
Definition Cabana_CommunicationPlanBase.hpp:465
Definition Cabana_CommunicationPlanBase.hpp:960
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_CommunicationPlanBase.hpp:374
buffer_type _send_buffer
Send buffer.
Definition Cabana_CommunicationPlanBase.hpp:735
void reallocateSend(const std::size_t num_send)
Resize the send buffer.
Definition Cabana_CommunicationPlanBase.hpp:724
typename particle_data_type::tuple_type data_type
Communication data type.
Definition Cabana_CommunicationPlanBase.hpp:706
AoSoAType particle_data_type
Particle data type.
Definition Cabana_CommunicationPlanBase.hpp:702
buffer_type _recv_buffer
Receive buffer.
Definition Cabana_CommunicationPlanBase.hpp:737
typename particle_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlanBase.hpp:704
particle_data_type _particles
Particle AoSoA.
Definition Cabana_CommunicationPlanBase.hpp:739
CommunicationDataAoSoA(particle_data_type particles)
Definition Cabana_CommunicationPlanBase.hpp:714
typename Kokkos::View< data_type *, memory_space > buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlanBase.hpp:708
std::size_t _num_comp
Slice components.
Definition Cabana_CommunicationPlanBase.hpp:741
void reallocateReceive(const std::size_t num_recv)
Resize the receive buffer.
Definition Cabana_CommunicationPlanBase.hpp:729
void setSliceComponents()
Get the total number of components in the slice.
Definition Cabana_CommunicationPlanBase.hpp:789
void reallocateSend(const std::size_t num_send)
Resize the send buffer.
Definition Cabana_CommunicationPlanBase.hpp:778
buffer_type _send_buffer
Send buffer.
Definition Cabana_CommunicationPlanBase.hpp:797
buffer_type _recv_buffer
Receive buffer.
Definition Cabana_CommunicationPlanBase.hpp:799
void reallocateReceive(const std::size_t num_recv)
Resize the receive buffer.
Definition Cabana_CommunicationPlanBase.hpp:783
typename Kokkos::View< data_type **, Kokkos::LayoutRight, memory_space > buffer_type
Communication buffer type.
Definition Cabana_CommunicationPlanBase.hpp:759
typename particle_data_type::value_type data_type
Communication data type.
Definition Cabana_CommunicationPlanBase.hpp:757
typename particle_data_type::memory_space memory_space
Kokkos memory space.
Definition Cabana_CommunicationPlanBase.hpp:755
SliceType particle_data_type
Particle data type.
Definition Cabana_CommunicationPlanBase.hpp:753
std::size_t _num_comp
Slice components.
Definition Cabana_CommunicationPlanBase.hpp:803
particle_data_type _particles
Particle slice.
Definition Cabana_CommunicationPlanBase.hpp:801
CommunicationDataSlice(particle_data_type particles)
Definition Cabana_CommunicationPlanBase.hpp:766
Definition Cabana_Types.hpp:88
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:868