Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_Grid_SparseHalo.hpp
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
12#ifndef CABANA_GRID_SPARSEHALO_HPP
13#define CABANA_GRID_SPARSEHALO_HPP
14
16#include <Cabana_SoA.hpp>
17#include <Cabana_Tuple.hpp>
18
19#include <Cabana_Grid_Halo.hpp> // to get the pattern and tags defined here
22#include <Cabana_Grid_Types.hpp>
23
24#include <Kokkos_Core.hpp>
25
26#include <numeric>
27#include <type_traits>
28
29namespace Cabana
30{
31namespace Grid
32{
33namespace Experimental
34{
35//---------------------------------------------------------------------------//
36// Halo
37// ---------------------------------------------------------------------------//
48template <class MemorySpace, class DataTypes, class EntityType,
49 std::size_t NumSpaceDim, unsigned long long cellBitsPerTileDim,
50 typename Value = int, typename Key = uint64_t>
52{
53 public:
55 static constexpr std::size_t num_space_dim = NumSpaceDim;
56
58 using memory_space = MemorySpace;
60 using entity_type = EntityType;
61
64
66 using value_type = Value;
68 using key_type = Key;
71 {
72 invalid_key = ~static_cast<key_type>( 0 )
73 };
74
76 using aosoa_member_types = DataTypes;
79
81 template <std::size_t M>
85 static constexpr std::size_t member_num = aosoa_member_types::size;
87 static constexpr unsigned long long cell_bits_per_tile_dim =
88 cellBitsPerTileDim;
90 static constexpr unsigned long long cell_num_per_tile =
91 1 << ( cell_bits_per_tile_dim * 3 );
92
94 using buffer_view = Kokkos::View<tuple_type*, memory_space>;
97 using steering_view = Kokkos::View<key_type*, memory_space>;
102 enum Index
103 {
104 own = 0,
105 ghost = 1,
106 total = 2
107 };
108
111 using counting_view = Kokkos::View<int[2], memory_space,
112 Kokkos::MemoryTraits<Kokkos::Atomic>>;
113
114 //---------------------------------------------------------------------------//
121 template <class SparseArrayType>
123 const std::shared_ptr<SparseArrayType>& sparse_array )
124 : _pattern( pattern )
125 {
126 // Function to get the local id of the neighbor.
127 auto neighbor_id = []( const std::array<int, num_space_dim>& ijk )
128 {
129 int id = ijk[0];
130 for ( std::size_t d = 1; d < num_space_dim; ++d )
131 id += num_space_dim * id + ijk[d];
132 return id;
133 };
134
135 // Neighbor id flip function. This lets us compute what neighbor we
136 // are relative to a given neighbor.
137 auto flip_id = [=]( const std::array<int, num_space_dim>& ijk )
138 {
139 std::array<int, num_space_dim> flip_ijk;
140 for ( std::size_t d = 0; d < num_space_dim; ++d )
141 flip_ijk[d] = -ijk[d];
142 return flip_ijk;
143 };
144
145 // compute total number of bytes in each SoA structure of the sparse
146 // grid (the spasre grid is in AoSoA manner)
147 auto soa_byte_array = compute_member_size_list();
148 for ( std::size_t i = 0; i < member_num; ++i )
149 _soa_member_bytes[i] = soa_byte_array[i];
150 _soa_total_bytes = std::max(
151 std::accumulate( soa_byte_array.begin(), soa_byte_array.end(), 0 ),
152 static_cast<int>( sizeof( tuple_type ) ) );
153
154 // Get the local grid the array uses.
155 auto local_grid = sparse_array->layout().localGrid();
156
157 // linear MPI rank ID of the current working rank
158 _self_rank =
159 local_grid->neighborRank( std::array<int, 3>( { 0, 0, 0 } ) );
160
161 // set the linear neighbor rank ID
162 // set up correspondence between sending and receiving buffers
163 auto neighbors = _pattern.getNeighbors();
164 for ( const auto& n : neighbors )
165 {
166 // neighbor rank linear ID
167 int rank = local_grid->neighborRank( n );
168
169 // if neighbor is valid
170 if ( rank >= 0 )
171 {
172 // add neighbor to the list
173 _neighbor_ranks.push_back( rank );
174 // set the tag to use for sending data to this neighbor
175 // the corresponding neighbor will have the same receiving tag
176 _send_tags.push_back( neighbor_id( n ) );
177 // set the tag to use for receiving data from this neighbor
178 // the corresponding neighbor will have the same sending tag
179 _receive_tags.push_back( neighbor_id( flip_id( n ) ) );
180
181 // build communication data for owned entries
182 buildCommData( Own(), local_grid, n, _owned_buffers,
183 _owned_tile_steering, _owned_tile_spaces );
184 // build communication data for ghosted entries
185 buildCommData( Ghost(), local_grid, n, _ghosted_buffers,
186 _ghosted_tile_steering, _ghosted_tile_spaces );
187
188 auto& own_index_space = _owned_tile_spaces.back();
189 auto& ghost_index_space = _ghosted_tile_spaces.back();
190 int tmp_steering_size =
191 own_index_space.sizeTile() > ghost_index_space.sizeTile()
192 ? own_index_space.sizeTile()
193 : ghost_index_space.sizeTile();
194 _tmp_tile_steering.push_back(
195 steering_view( "tmp_tile_steering", tmp_steering_size ) );
196
197 _valid_counting.push_back(
198 counting_view( "halo_valid_counting" ) );
199 _neighbor_counting.push_back(
200 counting_view( "halo_neighbor_valid_counting" ) );
201 Kokkos::deep_copy( _valid_counting.back(), 0 );
202 Kokkos::deep_copy( _neighbor_counting.back(), 0 );
203
204 _valid_neighbor_ids.emplace_back( n );
205 }
206 }
207 }
208
210 template <class SparseArrayType>
211 MPI_Comm getComm( const SparseArrayType sparse_array ) const
212 {
213 return sparse_array.layout().localGrid()->globalGrid().comm();
214 }
215
227 template <class DecompositionTag, class LocalGridType>
228 void buildCommData( DecompositionTag decomposition_tag,
229 const std::shared_ptr<LocalGridType>& local_grid,
230 const std::array<int, num_space_dim>& nid,
231 std::vector<buffer_view>& buffers,
232 std::vector<steering_view>& steering,
233 std::vector<tile_index_space>& spaces )
234 {
235 // get the halo sparse tile index space sharsed with the neighbor
236 spaces.push_back(
237 local_grid->template sharedTileIndexSpace<cell_bits_per_tile_dim>(
238 decomposition_tag, entity_type(), nid ) );
239 auto& index_space = spaces.back();
240
241 // allocate the buffer to store shared data with given neighbor
242 buffers.push_back(
243 buffer_view( "halo_buffer", index_space.sizeCell() ) );
244 // allocate the steering to guide the communication with the given
245 // neighbor
246 steering.push_back(
247 steering_view( "halo_tile_steering", index_space.sizeTile() ) );
248 // clear steering (init)
249 Kokkos::deep_copy( steering.back(), invalid_key );
250 }
251
252 //---------------------------------------------------------------------------//
258 template <class LocalGridType>
259 void updateTileSpace( const std::shared_ptr<LocalGridType>& local_grid )
260 {
261 // clear index space array first
262 _owned_tile_spaces.clear();
263 _ghosted_tile_spaces.clear();
264
265 // loop over all neighbors and update the shared tile index space
266 auto neighbors = _pattern.getNeighbors();
267 for ( std::size_t i = 0; i < _valid_neighbor_ids.size(); ++i )
268 {
269 // get neighbor relative id
270 auto& n = _valid_neighbor_ids[i];
271 // get neighbor linear MPI rank ID
272 int rank = local_grid->neighborRank( n );
273 // check if neighbor rank is valid
274 // the neighbor id should always be valid (as all should be
275 // well-prepared during construction/initialization)
276 if ( rank == _neighbor_ranks[i] )
277 {
278 // get shared tile index space from local grid
279 _owned_tile_spaces.push_back(
280 local_grid
281 ->template sharedTileIndexSpace<cell_bits_per_tile_dim>(
282 Own(), entity_type(), n ) );
283 _ghosted_tile_spaces.push_back(
284 local_grid
285 ->template sharedTileIndexSpace<cell_bits_per_tile_dim>(
286 Ghost(), entity_type(), n ) );
287
288 // reference to tile index spaces
289 auto& own_index_space = _owned_tile_spaces.back();
290 auto& ghost_index_space = _ghosted_tile_spaces.back();
291
292 // number of tiles inside each shared tile space
293 int own_tile_size = own_index_space.sizeTile();
294 int ghost_tile_size = ghost_index_space.sizeTile();
295 int tmp_steering_size = own_tile_size > ghost_tile_size
296 ? own_tile_size
297 : ghost_tile_size;
298
299 // check if the data steering and buffers require resize
300 // since the partition may changes during simulation process
301 // the size of shared spaces may also change accordingly
302 if ( own_tile_size > _owned_tile_steering[i].extent( 0 ) )
303 {
304 Kokkos::resize( _owned_tile_steering[i], own_tile_size );
305 Kokkos::resize( _owned_buffers[i],
306 own_index_space.sizeCell() );
307 }
308 if ( ghost_tile_size > _ghosted_tile_steering[i].extent( 0 ) )
309 {
310 Kokkos::resize( _ghosted_tile_steering[i],
311 ghost_tile_size );
312 Kokkos::resize( _ghosted_buffers[i],
313 ghost_index_space.sizeCell() );
314 }
315 if ( tmp_steering_size > _tmp_tile_steering[i].extent( 0 ) )
316 Kokkos::resize( _tmp_tile_steering[i], tmp_steering_size );
317 }
318 else
319 std::runtime_error( "neighbor rank doesn't match id" );
320 }
321 }
322
323 //---------------------------------------------------------------------------//
332 template <class ExecSpace, class SparseMapType>
333 void register_halo( SparseMapType& map )
334 {
335 // return if there's no valid neighbors
336 int num_n = _neighbor_ranks.size();
337 if ( 0 == num_n )
338 return;
339
340 // loop for all valid neighbors
341 for ( int nid = 0; nid < num_n; nid++ )
342 {
343 auto& owned_space = _owned_tile_spaces[nid];
344 auto& owned_steering = _owned_tile_steering[nid];
345
346 auto& ghosted_space = _ghosted_tile_spaces[nid];
347 auto& ghosted_steering = _ghosted_tile_steering[nid];
348
349 auto& counting = _valid_counting[nid];
350
351 // check the sparse map, if there are valid tiles in corresponding
352 // shared tile index space, add the tile key into the steering view,
353 // this steering keys will later be used for halo data collection
354
355 Kokkos::parallel_for(
356 Kokkos::RangePolicy<ExecSpace>( 0, map.capacity() ),
357 KOKKOS_LAMBDA( const int index ) {
358 if ( map.valid_at( index ) )
359 {
360 auto tile_key = map.key_at( index );
361 int ti, tj, tk;
362 map.key2ijk( tile_key, ti, tj, tk );
363 if ( owned_space.tileInRange( ti, tj, tk ) )
364 {
365 owned_steering( counting( Index::own )++ ) =
366 tile_key;
367 }
368 else if ( ghosted_space.tileInRange( ti, tj, tk ) )
369 {
370 ghosted_steering( counting( Index::ghost )++ ) =
371 tile_key;
372 }
373 }
374 } );
375 Kokkos::fence();
376 }
377 }
378
379 //---------------------------------------------------------------------------//
387 void clear( MPI_Comm comm )
388 {
389 // clear counting
390 for ( std::size_t i = 0; i < _valid_counting.size(); ++i )
391 Kokkos::deep_copy( _valid_counting[i], 0 );
392 for ( std::size_t i = 0; i < _neighbor_counting.size(); ++i )
393 Kokkos::deep_copy( _neighbor_counting[i], 0 );
394 // clear steering
395 for ( std::size_t i = 0; i < _owned_tile_steering.size(); ++i )
396 Kokkos::deep_copy( _owned_tile_steering[i], invalid_key );
397 for ( std::size_t i = 0; i < _ghosted_tile_steering.size(); ++i )
398 Kokkos::deep_copy( _ghosted_tile_steering[i], invalid_key );
399 for ( std::size_t i = 0; i < _tmp_tile_steering.size(); ++i )
400 Kokkos::deep_copy( _tmp_tile_steering[i], invalid_key );
401 // sync
402 MPI_Barrier( comm );
403 }
404
405 //---------------------------------------------------------------------------//
415 MPI_Comm comm, const bool is_neighbor_counting_collected = false ) const
416 {
417 // the valid halo size is already counted, no need to recount
418 if ( is_neighbor_counting_collected )
419 return;
420
421 // number of neighbors
422 int num_n = _neighbor_ranks.size();
423
424 // MPI request to collect counting information in shared owned and
425 // shared ghosted space
426 std::vector<MPI_Request> counting_requests( 2 * num_n,
427 MPI_REQUEST_NULL );
428 const int mpi_tag_counting = 1234;
429
430 // receive from all neighbors
431 for ( int nid = 0; nid < num_n; ++nid )
432 {
433 MPI_Irecv( _neighbor_counting[nid].data(),
434 Index::total * sizeof( int ), MPI_BYTE,
435 _neighbor_ranks[nid],
436 mpi_tag_counting + _receive_tags[nid], comm,
437 &counting_requests[nid] );
438 }
439 // send to all valid neighbors
440 for ( int nid = 0; nid < num_n; ++nid )
441 {
442 MPI_Isend( _valid_counting[nid].data(),
443 Index::total * sizeof( int ), MPI_BYTE,
444 _neighbor_ranks[nid], mpi_tag_counting + _send_tags[nid],
445 comm, &counting_requests[nid + num_n] );
446 }
447
448 // wait until all counting data sending finished
449 const int ec = MPI_Waitall( num_n, counting_requests.data() + num_n,
450 MPI_STATUSES_IGNORE );
451
452 // check if the counting communication succeed
453 if ( MPI_SUCCESS != ec )
454 throw std::logic_error( "sparse_halo: counting sending failed." );
455 MPI_Barrier( comm );
456 }
457
468 MPI_Comm comm, std::vector<int>& valid_sends,
469 std::vector<int>& valid_recvs,
470 const bool is_neighbor_counting_collected = false ) const
471 {
472 // collect neighbor counting if needed
473 collectNeighborCounting( comm, is_neighbor_counting_collected );
474
475 // loop over all valid neighbors to check if there's data communication
476 // needed
477 for ( std::size_t nid = 0; nid < _neighbor_ranks.size(); ++nid )
478 {
479 // reference to counting in owned and ghosted share spaces
480 auto h_counting = Kokkos::create_mirror_view_and_copy(
481 Kokkos::HostSpace(), _valid_counting[nid] );
482 auto h_neighbor_counting = Kokkos::create_mirror_view_and_copy(
483 Kokkos::HostSpace(), _neighbor_counting[nid] );
484
485 // if the current ghosted space and the neighbor's owned share
486 // space is non-emty, we need to send data to the neighbor
487 if ( !( h_counting( Index::ghost ) == 0 ||
488 h_neighbor_counting( Index::own ) == 0 ) )
489 {
490 valid_sends.push_back( nid );
491 }
492 // if the current owned share space and the neighbor's ghosted share
493 // space is non-emty, the neighbor will send data to us and we need
494 // to receive data accordingly
495 if ( !( h_counting( Index::own ) == 0 ||
496 h_neighbor_counting( Index::ghost ) == 0 ) )
497 {
498 valid_recvs.push_back( nid );
499 }
500 }
501 }
502
513 MPI_Comm comm, std::vector<int>& valid_sends,
514 std::vector<int>& valid_recvs,
515 const bool is_neighbor_counting_collected = false ) const
516 {
517 // collect neighbor counting if needed
518 collectNeighborCounting( comm, is_neighbor_counting_collected );
519
520 // loop over all valid neighbors to check if there's data communication
521 // needed
522 for ( std::size_t nid = 0; nid < _neighbor_ranks.size(); ++nid )
523 {
524 auto h_counting = Kokkos::create_mirror_view_and_copy(
525 Kokkos::HostSpace(), _valid_counting[nid] );
526 auto h_neighbor_counting = Kokkos::create_mirror_view_and_copy(
527 Kokkos::HostSpace(), _neighbor_counting[nid] );
528
529 // if the current owned space and the neighbor's ghosted share
530 // space is non-emty, we need to send data to the neighbor
531 if ( !( h_counting( Index::own ) == 0 ||
532 h_neighbor_counting( Index::ghost ) == 0 ) )
533 {
534 valid_sends.push_back( nid );
535 }
536
537 // if the current ghosted space and the neighbor's owned share
538 // space is non-emty, we need to send data to the neighbor
539 if ( !( h_counting( Index::ghost ) == 0 ||
540 h_neighbor_counting( Index::own ) == 0 ) )
541 {
542 valid_recvs.push_back( nid );
543 }
544 }
545 }
546
558 template <class ExecSpace, class SparseArrayType>
559 void gather( const ExecSpace& exec_space, SparseArrayType& sparse_array,
560 const bool is_neighbor_counting_collected = false ) const
561 {
562 // return if no valid neighbor
563 if ( 0 == _neighbor_ranks.size() )
564 return;
565
566 // Get the MPI communicator.
567 auto comm = getComm( sparse_array );
568
569 const auto& map = sparse_array.layout().sparseMap();
570
571 // communicate "counting" among neighbors, to decide if the grid data
572 // communication is needed
573 std::vector<int> valid_sends;
574 std::vector<int> valid_recvs;
575 gatherValidSendAndRecvRanks( comm, valid_sends, valid_recvs,
576 is_neighbor_counting_collected );
577 MPI_Barrier( comm );
578
579 // ------------------------------------------------------------------
580 // communicate steering (array keys) for all valid sends and receives
581 std::vector<MPI_Request> steering_requests(
582 valid_recvs.size() + valid_sends.size(), MPI_REQUEST_NULL );
583 const int mpi_tag_steering = 3214;
584
585 // get the steering keys from valid neighbors to get all grids that
586 // we need to receive
587 // loop over all neighbors that will send data to the current rank
588 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
589 {
590 int nid = valid_recvs[i];
591 Kokkos::View<int[2], Kokkos::HostSpace> h_neighbor_counting(
592 "tmp_host_neighbor_counting" );
593 Kokkos::deep_copy( h_neighbor_counting, _neighbor_counting[nid] );
594
595 MPI_Irecv( _tmp_tile_steering[nid].data(),
596 h_neighbor_counting( Index::own ) * sizeof( key_type ),
597 MPI_BYTE, _neighbor_ranks[nid],
598 mpi_tag_steering + _receive_tags[nid], comm,
599 &steering_requests[i] );
600 }
601
602 // send the steering keys to valid neighbors
603 // loop over all neighbors that requires our owned data
604 for ( std::size_t i = 0; i < valid_sends.size(); ++i )
605 {
606 int nid = valid_sends[i];
607 Kokkos::View<int[2], Kokkos::HostSpace> h_counting(
608 "tmp_host_counting" );
609 Kokkos::deep_copy( h_counting, _valid_counting[nid] );
610
611 MPI_Isend( _owned_tile_steering[nid].data(),
612 h_counting( Index::own ) * sizeof( key_type ), MPI_BYTE,
613 _neighbor_ranks[nid], mpi_tag_steering + _send_tags[nid],
614 comm, &steering_requests[i + valid_recvs.size()] );
615 }
616
617 // wait for all sending work finish
618 const int ec_ss = MPI_Waitall(
619 valid_sends.size(), steering_requests.data() + valid_recvs.size(),
620 MPI_STATUSES_IGNORE );
621 if ( MPI_SUCCESS != ec_ss )
622 throw std::logic_error(
623 "sparse_halo_gather: steering sending failed." );
624 MPI_Barrier( comm );
625
626 // ------------------------------------------------------------------
627 // communicate sparse array data
628 // Pick a tag to use for communication. This object has its own
629 // communication space so any tag will do.
630 std::vector<MPI_Request> requests(
631 valid_recvs.size() + valid_sends.size(), MPI_REQUEST_NULL );
632 const int mpi_tag = 2345;
633
634 // post receives
635 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
636 {
637 int nid = valid_recvs[i];
638 Kokkos::View<int[2], Kokkos::HostSpace> h_neighbor_counting(
639 "tmp_host_neighbor_counting" );
640 ;
641 Kokkos::deep_copy( h_neighbor_counting, _neighbor_counting[nid] );
642
643 MPI_Irecv( _ghosted_buffers[nid].data(),
644 h_neighbor_counting( Index::own ) * cell_num_per_tile *
645 _soa_total_bytes,
646 MPI_BYTE, _neighbor_ranks[nid],
647 mpi_tag + _receive_tags[nid], comm, &requests[i] );
648 }
649
650 // pack send buffers and post sends
651 for ( std::size_t i = 0; i < valid_sends.size(); ++i )
652 {
653 int nid = valid_sends[i];
654 Kokkos::View<int[2], Kokkos::HostSpace> h_counting(
655 "tmp_host_counting" );
656 ;
657 Kokkos::deep_copy( h_counting, _valid_counting[nid] );
658
659 packBuffer( exec_space, _owned_buffers[nid],
660 _owned_tile_steering[nid], sparse_array,
661 h_counting( Index::own ) );
662 Kokkos::fence();
663
664 MPI_Isend(
665 _owned_buffers[nid].data(),
666 h_counting( Index::own ) * cell_num_per_tile * _soa_total_bytes,
667 MPI_BYTE, _neighbor_ranks[nid], mpi_tag + _send_tags[nid], comm,
668 &requests[i + valid_recvs.size()] );
669 }
670
671 // unpack receive buffers
672 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
673 {
674 // get the next buffer to unpack
675 int unpack_index = MPI_UNDEFINED;
676 MPI_Waitany( valid_recvs.size(), requests.data(), &unpack_index,
677 MPI_STATUS_IGNORE );
678
679 // in theory we should receive enough buffers to unpack
680 // if not there could be some problems
681 if ( MPI_UNDEFINED == unpack_index )
682 std::runtime_error(
683 std::string( "sparse_halo_gather: data receiving failed, "
684 "get only " ) +
685 std::to_string( i ) + ", need " +
686 std::to_string( valid_recvs.size() ) );
687 // otherwise unpack the next buffer
688 else
689 {
690 int nid = valid_recvs[unpack_index];
691 auto h_neighbor_counting = Kokkos::create_mirror_view_and_copy(
692 Kokkos::HostSpace(), _neighbor_counting[nid] );
694 _ghosted_buffers[nid], _tmp_tile_steering[nid],
695 sparse_array, map,
696 h_neighbor_counting( Index::own ) );
697 Kokkos::fence();
698 }
699 }
700
701 // wait to finish all send requests
702 const int ec_data = MPI_Waitall( valid_sends.size(),
703 requests.data() + valid_recvs.size(),
704 MPI_STATUSES_IGNORE );
705 if ( MPI_SUCCESS != ec_data )
706 throw std::logic_error(
707 "sparse_halo_gather: data sending failed." );
708
709 // reinit steerings for next round of communication
710 for ( std::size_t i = 0; i < _tmp_tile_steering.size(); ++i )
711 Kokkos::deep_copy( _tmp_tile_steering[i], invalid_key );
712 MPI_Barrier( comm );
713 }
714
729 template <class ExecSpace, class ReduceOp, class SparseArrayType>
730 void scatter( const ExecSpace& exec_space, const ReduceOp& reduce_op,
731 SparseArrayType& sparse_array,
732 const bool is_neighbor_counting_collected = false ) const
733 {
734 // return if no valid neighbor
735 if ( 0 == _neighbor_ranks.size() )
736 return;
737
738 // Get the MPI communicator.
739 auto comm = getComm( sparse_array );
740
741 const auto& map = sparse_array.layout().sparseMap();
742
743 // communicate "counting" among neighbors, to decide if the grid data
744 // transfer is needed
745 std::vector<int> valid_sends;
746 std::vector<int> valid_recvs;
747 scatterValidSendAndRecvRanks( comm, valid_sends, valid_recvs,
748 is_neighbor_counting_collected );
749 MPI_Barrier( comm );
750
751 // ------------------------------------------------------------------
752 // communicate steering (array keys) for all valid sends and receives
753 std::vector<MPI_Request> steering_requests(
754 valid_recvs.size() + valid_sends.size(), MPI_REQUEST_NULL );
755 const int mpi_tag_steering = 214;
756
757 // get the steering keys from valid neighbors to know all grids that
758 // we need to receive
759 // loop over all neighbors that will send data to the current rank
760 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
761 {
762 int nid = valid_recvs[i];
763 Kokkos::View<int[2], Kokkos::HostSpace> h_neighbor_counting(
764 "tmp_host_neighbor_counting" );
765 ;
766 Kokkos::deep_copy( h_neighbor_counting, _neighbor_counting[nid] );
767
768 MPI_Irecv( _tmp_tile_steering[nid].data(),
769 h_neighbor_counting( Index::ghost ) * sizeof( key_type ),
770 MPI_BYTE, _neighbor_ranks[nid],
771 mpi_tag_steering + _receive_tags[nid], comm,
772 &steering_requests[i] );
773 }
774
775 // send the steering keys to valid neighbors
776 // loop over all neighbors that requires our owned data
777 for ( std::size_t i = 0; i < valid_sends.size(); ++i )
778 {
779 int nid = valid_sends[i];
780 Kokkos::View<int[2], Kokkos::HostSpace> h_counting(
781 "tmp_host_counting" );
782 ;
783 Kokkos::deep_copy( h_counting, _valid_counting[nid] );
784
785 MPI_Isend( _ghosted_tile_steering[nid].data(),
786 h_counting( Index::ghost ) * sizeof( key_type ),
787 MPI_BYTE, _neighbor_ranks[nid],
788 mpi_tag_steering + _send_tags[nid], comm,
789 &steering_requests[i + valid_recvs.size()] );
790 }
791
792 // wait for all sending work finish
793 const int ec_ss = MPI_Waitall(
794 valid_sends.size(), steering_requests.data() + valid_recvs.size(),
795 MPI_STATUSES_IGNORE );
796 if ( MPI_SUCCESS != ec_ss )
797 throw std::logic_error(
798 "sparse_halo_scatter: steering sending failed." );
799 MPI_Barrier( comm );
800
801 // ------------------------------------------------------------------
802 // communicate sparse array data
803 // Pick a tag to use for communication. This object has its own
804 // communication space so any tag will do.
805 std::vector<MPI_Request> requests(
806 valid_recvs.size() + valid_sends.size(), MPI_REQUEST_NULL );
807 const int mpi_tag = 345;
808
809 // post receives
810 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
811 {
812 int nid = valid_recvs[i];
813 Kokkos::View<int[2], Kokkos::HostSpace> h_neighbor_counting(
814 "tmp_host_neighbor_counting" );
815 ;
816 Kokkos::deep_copy( h_neighbor_counting, _neighbor_counting[nid] );
817
818 MPI_Irecv( _owned_buffers[nid].data(),
819 h_neighbor_counting( Index::ghost ) * cell_num_per_tile *
820 _soa_total_bytes,
821 MPI_BYTE, _neighbor_ranks[nid],
822 mpi_tag + _receive_tags[nid], comm, &requests[i] );
823 }
824
825 // pack send buffers and post sends
826 for ( std::size_t i = 0; i < valid_sends.size(); ++i )
827 {
828 int nid = valid_sends[i];
829 Kokkos::View<int[2], Kokkos::HostSpace> h_counting(
830 "tmp_host_counting" );
831 ;
832 Kokkos::deep_copy( h_counting, _valid_counting[nid] );
833 packBuffer( exec_space, _ghosted_buffers[nid],
834 _ghosted_tile_steering[nid], sparse_array,
835 h_counting( Index::ghost ) );
836 Kokkos::fence();
837
838 MPI_Isend( _ghosted_buffers[nid].data(),
839 h_counting( Index::ghost ) * cell_num_per_tile *
840 _soa_total_bytes,
841 MPI_BYTE, _neighbor_ranks[nid],
842 mpi_tag + _send_tags[nid], comm,
843 &requests[i + valid_recvs.size()] );
844 }
845
846 // unpack receive buffers
847 for ( std::size_t i = 0; i < valid_recvs.size(); ++i )
848 {
849 // get the next buffer to unpack
850 int unpack_index = MPI_UNDEFINED;
851 MPI_Waitany( valid_recvs.size(), requests.data(), &unpack_index,
852 MPI_STATUS_IGNORE );
853
854 // in theory we should receive enough buffers to unpack
855 // if not there could be some problems
856 if ( MPI_UNDEFINED == unpack_index )
857 std::runtime_error(
858 std::string( "sparse_halo_scatter: data receiving failed, "
859 "get only " ) +
860 std::to_string( i ) + ", need " +
861 std::to_string( valid_recvs.size() ) );
862 // otherwise unpack the next buffer with the given reduce operator
863 else
864 {
865 int nid = valid_recvs[unpack_index];
866 auto h_neighbor_counting = Kokkos::create_mirror_view_and_copy(
867 Kokkos::HostSpace(), _neighbor_counting[nid] );
868 unpackBuffer( reduce_op, exec_space, _owned_buffers[nid],
869 _tmp_tile_steering[nid], sparse_array, map,
870 h_neighbor_counting( Index::ghost ) );
871 Kokkos::fence();
872 }
873 }
874
875 // wait to finish all send requests
876 const int ec_data = MPI_Waitall( valid_sends.size(),
877 requests.data() + valid_recvs.size(),
878 MPI_STATUSES_IGNORE );
879 if ( MPI_SUCCESS != ec_data )
880 throw std::logic_error(
881 "sparse_halo_scatter: data sending failed." );
882
883 // reinit steerings for next round of communication
884 for ( std::size_t i = 0; i < _tmp_tile_steering.size(); ++i )
885 Kokkos::deep_copy( _tmp_tile_steering[i], invalid_key );
886 MPI_Barrier( comm );
887 }
888
889 //---------------------------------------------------------------------------//
900 template <class ExecSpace, class SparseArrayType>
901 void packBuffer( const ExecSpace& exec_space, const buffer_view& buffer,
902 const steering_view& tile_steering,
903 SparseArrayType& sparse_array, const int count ) const
904 {
905 Kokkos::parallel_for(
906 "pack_spares_halo_buffer",
907 Kokkos::RangePolicy<ExecSpace>( exec_space, 0, count ),
908 KOKKOS_LAMBDA( const int i ) {
909 if ( tile_steering( i ) != invalid_key )
910 {
911 const int buffer_idx = i * cell_num_per_tile;
912 auto tile_key = tile_steering( i );
913 for ( int lcid = 0; lcid < (int)cell_num_per_tile; ++lcid )
914 {
915 buffer( buffer_idx + lcid ) =
916 sparse_array.getTuple( tile_key, lcid );
917 }
918 }
919 } );
920 }
921
922 //---------------------------------------------------------------------------//
924 template <class T>
925 KOKKOS_INLINE_FUNCTION static void
926 unpackOp( ScatterReduce::Sum, const T& buffer_val, T& array_val )
927 {
928 array_val += buffer_val;
929 }
930
932 template <class T>
933 KOKKOS_INLINE_FUNCTION static void
934 unpackOp( ScatterReduce::Min, const T& buffer_val, T& array_val )
935 {
936 if ( buffer_val < array_val )
937 array_val = buffer_val;
938 }
939
941 template <class T>
942 KOKKOS_INLINE_FUNCTION static void
943 unpackOp( ScatterReduce::Max, const T& buffer_val, T& array_val )
944 {
945 if ( buffer_val > array_val )
946 array_val = buffer_val;
947 }
948
950 template <class T>
951 KOKKOS_INLINE_FUNCTION static void
952 unpackOp( ScatterReduce::Replace, const T& buffer_val, T& array_val )
953 {
954 array_val = buffer_val;
955 }
956
957 //---------------------------------------------------------------------------//
971 template <class ReduceOp, std::size_t N, std::size_t M, class SoAType>
972 KOKKOS_FORCEINLINE_FUNCTION static std::enable_if_t<3 == M, void>
973 unpackTupleMember( const ReduceOp& reduce_op, const tuple_type& src_tuple,
974 SoAType& dst_soa, const int soa_idx,
975 const Kokkos::Array<std::size_t, M>& extents,
976 const std::integral_constant<std::size_t, N>,
977 const std::integral_constant<std::size_t, M> )
978 {
979 for ( std::size_t d0 = 0; d0 < extents[0]; ++d0 )
980 for ( int d1 = 0; d1 < extents[1]; ++d1 )
981 for ( int d2 = 0; d2 < extents[2]; ++d2 )
982 {
983 unpackOp( reduce_op,
984 Cabana::get<N>( src_tuple, d0, d1, d2 ),
985 Cabana::get<N>( dst_soa, soa_idx, d0, d1, d2 ) );
986 }
987 }
988
1002 template <class ReduceOp, std::size_t N, std::size_t M, class SoAType>
1003 KOKKOS_FORCEINLINE_FUNCTION static std::enable_if_t<2 == M, void>
1004 unpackTupleMember( const ReduceOp& reduce_op, const tuple_type& src_tuple,
1005 SoAType& dst_soa, const int soa_idx,
1006 const Kokkos::Array<std::size_t, M>& extents,
1007 const std::integral_constant<std::size_t, N>,
1008 const std::integral_constant<std::size_t, M> )
1009 {
1010 for ( std::size_t d0 = 0; d0 < extents[0]; ++d0 )
1011 for ( int d1 = 0; d1 < extents[1]; ++d1 )
1012 {
1013 unpackOp( reduce_op, Cabana::get<N>( src_tuple, d0, d1 ),
1014 Cabana::get<N>( dst_soa, soa_idx, d0, d1 ) );
1015 }
1016 }
1017
1031 template <class ReduceOp, std::size_t N, std::size_t M, class SoAType>
1032 KOKKOS_FORCEINLINE_FUNCTION static std::enable_if_t<1 == M, void>
1033 unpackTupleMember( const ReduceOp& reduce_op, const tuple_type& src_tuple,
1034 SoAType& dst_soa, const int soa_idx,
1035 const Kokkos::Array<std::size_t, M>& extents,
1036 const std::integral_constant<std::size_t, N>,
1037 const std::integral_constant<std::size_t, M> )
1038 {
1039 for ( std::size_t d0 = 0; d0 < extents[0]; ++d0 )
1040 {
1041 unpackOp( reduce_op, Cabana::get<N>( src_tuple, d0 ),
1042 Cabana::get<N>( dst_soa, soa_idx, d0 ) );
1043 }
1044 }
1045
1058 template <class ReduceOp, std::size_t N, std::size_t M, class SoAType>
1059 KOKKOS_FORCEINLINE_FUNCTION static std::enable_if_t<0 == M, void>
1060 unpackTupleMember( const ReduceOp& reduce_op, const tuple_type& src_tuple,
1061 SoAType& dst_soa, const int soa_idx,
1062 const Kokkos::Array<std::size_t, M>&,
1063 const std::integral_constant<std::size_t, N>,
1064 const std::integral_constant<std::size_t, M> )
1065 {
1066 unpackOp( reduce_op, Cabana::get<N>( src_tuple ),
1067 Cabana::get<N>( dst_soa, soa_idx ) );
1068 }
1069
1079 template <class ReduceOp, class SoAType>
1080 KOKKOS_FORCEINLINE_FUNCTION static void
1081 unpackTuple( const ReduceOp& reduce_op, const tuple_type& src_tuple,
1082 SoAType& dst_soa, const int soa_idx,
1083 const std::integral_constant<std::size_t, 0> )
1084 {
1085 using current_type = member_data_type<0>;
1086 auto extents = compute_member_extents<current_type>();
1088 reduce_op, src_tuple, dst_soa, soa_idx, extents,
1089 std::integral_constant<std::size_t, 0>(),
1090 std::integral_constant<std::size_t,
1091 std::rank<current_type>::value>() );
1092 }
1093
1104 template <class ReduceOp, std::size_t N, class SoAType>
1105 KOKKOS_FORCEINLINE_FUNCTION static void
1106 unpackTuple( const ReduceOp& reduce_op, const tuple_type& src_tuple,
1107 SoAType& dst_soa, const int soa_idx,
1108 const std::integral_constant<std::size_t, N> )
1109 {
1110 using current_type = member_data_type<N>;
1111 auto extents = compute_member_extents<current_type>();
1113 reduce_op, src_tuple, dst_soa, soa_idx, extents,
1114 std::integral_constant<std::size_t, N>(),
1115 std::integral_constant<std::size_t,
1116 std::rank<current_type>::value>() );
1117
1118 if ( N > 1 )
1119 {
1120 // recurcively unpack the next tuple element
1121 unpackTuple( reduce_op, src_tuple, dst_soa, soa_idx,
1122 std::integral_constant<std::size_t, N - 1>() );
1123 }
1124 else
1125 {
1126 unpackTuple( reduce_op, src_tuple, dst_soa, soa_idx,
1127 std::integral_constant<std::size_t, 0>() );
1128 }
1129 }
1130
1145 template <class ReduceOp, class ExecSpace, class SparseArrayType,
1146 class SparseMapType>
1147 void unpackBuffer( const ReduceOp& reduce_op, const ExecSpace& exec_space,
1148 const buffer_view& buffer,
1149 const steering_view& tile_steering,
1150 const SparseArrayType& sparse_array, SparseMapType& map,
1151 const int count ) const
1152 {
1153 Kokkos::parallel_for(
1154 "unpack_spares_halo_buffer",
1155 Kokkos::RangePolicy<ExecSpace>( exec_space, 0, count ),
1156 KOKKOS_LAMBDA( const int i ) {
1157 if ( tile_steering( i ) != invalid_key )
1158 {
1159 auto tile_key = tile_steering( i );
1160 if ( map.isValidKey( tile_key ) )
1161 {
1162 int ti, tj, tk;
1163 map.key2ijk( tile_key, ti, tj, tk );
1164
1165 auto tile_id = map.queryTileFromTileKey( tile_key );
1166 const int buffer_idx = i * cell_num_per_tile;
1167 for ( int lcid = 0; lcid < (int)cell_num_per_tile;
1168 ++lcid )
1169 {
1170 auto& tuple = buffer( buffer_idx + lcid );
1171 auto& data_access =
1172 sparse_array.accessTile( tile_id );
1174 reduce_op, tuple, data_access, lcid,
1175 std::integral_constant<std::size_t,
1176 member_num - 1>() );
1177 }
1178 }
1179 }
1180 } );
1181 }
1182
1183 private:
1184 // These functions may be useful if added to Cabana_MemberType.hpp
1185 // compute member size
1186 template <std::size_t M>
1187 static constexpr std::size_t compute_member_size()
1188 {
1189 return sizeof( member_data_type<M> );
1190 }
1191
1192 template <typename Sequence>
1193 struct compute_member_size_list_impl;
1194
1195 template <std::size_t... Is>
1196 struct compute_member_size_list_impl<std::index_sequence<Is...>>
1197 {
1198 std::array<std::size_t, member_num> operator()()
1199 {
1200 return { compute_member_size<Is>()... };
1201 }
1202 };
1203
1204 template <std::size_t N = member_num,
1205 typename Indices = std::make_index_sequence<N>>
1206 std::array<std::size_t, member_num> compute_member_size_list()
1207 {
1208 compute_member_size_list_impl<Indices> op;
1209 return op();
1210 }
1211
1212 // member extent
1213 template <typename Type, std::size_t M>
1214 KOKKOS_FORCEINLINE_FUNCTION static constexpr std::size_t
1215 compute_one_member_extent()
1216 {
1217 return std::extent<Type, M>::value;
1218 }
1219
1220 template <class Type, std::size_t M, typename Sequence>
1221 struct compute_member_extents_impl;
1222
1223 template <class Type, std::size_t M, std::size_t... Is>
1224 struct compute_member_extents_impl<Type, M, std::index_sequence<Is...>>
1225 {
1226 KOKKOS_FORCEINLINE_FUNCTION
1227 Kokkos::Array<std::size_t, M> operator()()
1228 {
1229 return { compute_one_member_extent<Type, Is>()... };
1230 }
1231 };
1232
1233 template <class Type, std::size_t M = std::rank<Type>::value,
1234 typename Indices = std::make_index_sequence<M>>
1235 KOKKOS_FORCEINLINE_FUNCTION static Kokkos::Array<std::size_t, M>
1236 compute_member_extents()
1237 {
1238 compute_member_extents_impl<Type, M, Indices> op;
1239 return op();
1240 }
1241
1242 private:
1243 // Current MPI linear rank ID
1244 int _self_rank;
1245 // Hallo pattern
1246 halo_pattern_type _pattern;
1247
1248 // neighbor rank linear MPI rank IDs
1249 std::vector<int> _neighbor_ranks;
1250 // valid neigber rank indices; valid means require data communication
1251 std::vector<std::array<int, num_space_dim>> _valid_neighbor_ids;
1252 // sending tags
1253 std::vector<int> _send_tags;
1254 // receiving tags
1255 std::vector<int> _receive_tags;
1256
1257 // owned view buffers
1258 std::vector<buffer_view> _owned_buffers;
1259 // ghosted view buffers
1260 std::vector<buffer_view> _ghosted_buffers;
1261
1262 // owned tile key steerings
1263 std::vector<steering_view> _owned_tile_steering;
1264 // key steering buffers (used to store valid keys get from neighbors)
1265 std::vector<steering_view> _tmp_tile_steering;
1266 // ghosted tile key steerings
1267 std::vector<steering_view> _ghosted_tile_steering;
1268
1269 // valid halo grid counting on current rank (each element map to a neighbor)
1270 std::vector<counting_view> _valid_counting;
1271 // valid halo grid counting on corresponding neighbor ranks
1272 std::vector<counting_view> _neighbor_counting;
1273
1274 // owned tile space
1275 std::vector<tile_index_space> _owned_tile_spaces;
1276 // ghosted tile space
1277 std::vector<tile_index_space> _ghosted_tile_spaces;
1278
1279 // SoA member bytes num
1280 Kokkos::Array<std::size_t, member_num> _soa_member_bytes;
1281 // SoA total bytes count
1282 std::size_t _soa_total_bytes;
1283};
1284
1285//---------------------------------------------------------------------------//
1286// Sparse halo creation.
1287//---------------------------------------------------------------------------//
1293template <class MemorySpace, unsigned long long cellBitsPerTileDim,
1294 class DataTypes, class EntityType, class MeshType,
1295 class SparseMapType, class Pattern, typename Value = int,
1296 typename Key = uint64_t>
1297auto createSparseHalo(
1298 const Pattern& pattern,
1299 const std::shared_ptr<SparseArray<DataTypes, MemorySpace, EntityType,
1300 MeshType, SparseMapType>>
1301 array )
1302{
1303 using array_type = SparseArray<DataTypes, MemorySpace, EntityType, MeshType,
1304 SparseMapType>;
1305 using memory_space = typename array_type::memory_space;
1306 static constexpr std::size_t num_space_dim = array_type::num_space_dim;
1307 return std::make_shared<
1308 SparseHalo<memory_space, DataTypes, EntityType, num_space_dim,
1309 cellBitsPerTileDim, Value, Key>>( pattern, array );
1310}
1311
1312} // namespace Experimental
1313} // namespace Grid
1314} // namespace Cabana
1315
1316#endif // CABANA_GRID_SPARSEHALO_HPP
Multi-node grid scatter/gather.
Sparse grid fields arrays using AoSoA.
Grid type tags.
AoSoA tuple member types.
Struct-of-Arrays for building AoSoA.
Tuple of single particle information to build AoSoA.
Sparse array of field data on the local sparse mesh; Array data is stored in AoSoA manner,...
Definition Cabana_Grid_SparseArray.hpp:316
Definition Cabana_Grid_SparseHalo.hpp:52
static KOKKOS_INLINE_FUNCTION void unpackOp(ScatterReduce::Min, const T &buffer_val, T &array_val)
Reduce an element into the buffer. Min reduction.
Definition Cabana_Grid_SparseHalo.hpp:934
void gather(const ExecSpace &exec_space, SparseArrayType &sparse_array, const bool is_neighbor_counting_collected=false) const
Gather data into our ghosted share space from their owners.
Definition Cabana_Grid_SparseHalo.hpp:559
DataTypes aosoa_member_types
data members in AoSoA structure
Definition Cabana_Grid_SparseHalo.hpp:76
static KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t< 2==M, void > unpackTupleMember(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const Kokkos::Array< std::size_t, M > &extents, const std::integral_constant< std::size_t, N >, const std::integral_constant< std::size_t, M >)
Unpack a sparse arrays element (a tuple) in a buffer (for case tuple members with rank == 2)
Definition Cabana_Grid_SparseHalo.hpp:1004
Kokkos::View< key_type *, memory_space > steering_view
Definition Cabana_Grid_SparseHalo.hpp:97
void register_halo(SparseMapType &map)
register valid halos (according to grid activation status in sparse map) in the steerings
Definition Cabana_Grid_SparseHalo.hpp:333
Index
index (own or ghost)
Definition Cabana_Grid_SparseHalo.hpp:103
typename Cabana::MemberTypeAtIndex< M, aosoa_member_types >::type member_data_type
AoSoA member data type.
Definition Cabana_Grid_SparseHalo.hpp:82
static KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t< 3==M, void > unpackTupleMember(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const Kokkos::Array< std::size_t, M > &extents, const std::integral_constant< std::size_t, N >, const std::integral_constant< std::size_t, M >)
Unpack a sparse arrays element (a tuple) in a buffer (for case tuple members with rank == 3)
Definition Cabana_Grid_SparseHalo.hpp:973
static KOKKOS_INLINE_FUNCTION void unpackOp(ScatterReduce::Replace, const T &buffer_val, T &array_val)
Reduce an element into the buffer. Replace reduction.
Definition Cabana_Grid_SparseHalo.hpp:952
static KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t< 0==M, void > unpackTupleMember(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const Kokkos::Array< std::size_t, M > &, const std::integral_constant< std::size_t, N >, const std::integral_constant< std::size_t, M >)
Unpack a sparse arrays element (a tuple) in a buffer (for case tuple members with rank == 0)
Definition Cabana_Grid_SparseHalo.hpp:1060
void updateTileSpace(const std::shared_ptr< LocalGridType > &local_grid)
update tile index space according to current partition
Definition Cabana_Grid_SparseHalo.hpp:259
void scatter(const ExecSpace &exec_space, const ReduceOp &reduce_op, SparseArrayType &sparse_array, const bool is_neighbor_counting_collected=false) const
Scatter data from our ghosts to their owners using the given type of reduce operation.
Definition Cabana_Grid_SparseHalo.hpp:730
void gatherValidSendAndRecvRanks(MPI_Comm comm, std::vector< int > &valid_sends, std::vector< int > &valid_recvs, const bool is_neighbor_counting_collected=false) const
collect all valid ranks for sparse grid gather operations
Definition Cabana_Grid_SparseHalo.hpp:512
static constexpr std::size_t member_num
AoSoA member #.
Definition Cabana_Grid_SparseHalo.hpp:85
EntityType entity_type
entity type on sparse grid
Definition Cabana_Grid_SparseHalo.hpp:60
SparseHalo(const halo_pattern_type pattern, const std::shared_ptr< SparseArrayType > &sparse_array)
constructor
Definition Cabana_Grid_SparseHalo.hpp:122
KeyValue
invalid key in sparse map
Definition Cabana_Grid_SparseHalo.hpp:71
Key key_type
key type in sparse map
Definition Cabana_Grid_SparseHalo.hpp:68
static KOKKOS_FORCEINLINE_FUNCTION void unpackTuple(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const std::integral_constant< std::size_t, 0 >)
Unpack a sparse arrays tuple for it's member with index 0.
Definition Cabana_Grid_SparseHalo.hpp:1081
NodeHaloPattern< NumSpaceDim > halo_pattern_type
sparse grid halo pattern (TODO currently reusing Halo's Node pattern)
Definition Cabana_Grid_SparseHalo.hpp:63
static KOKKOS_INLINE_FUNCTION void unpackOp(ScatterReduce::Sum, const T &buffer_val, T &array_val)
Reduce an element into the buffer. Sum reduction.
Definition Cabana_Grid_SparseHalo.hpp:926
MPI_Comm getComm(const SparseArrayType sparse_array) const
Get the communicator.
Definition Cabana_Grid_SparseHalo.hpp:211
void clear(MPI_Comm comm)
clear guiding information in sparse halo,
Definition Cabana_Grid_SparseHalo.hpp:387
void packBuffer(const ExecSpace &exec_space, const buffer_view &buffer, const steering_view &tile_steering, SparseArrayType &sparse_array, const int count) const
Pack sparse arrays at halo regions into a buffer.
Definition Cabana_Grid_SparseHalo.hpp:901
Kokkos::View< int[2], memory_space, Kokkos::MemoryTraits< Kokkos::Atomic > > counting_view
Definition Cabana_Grid_SparseHalo.hpp:111
Value value_type
value type of entities on sparse grid
Definition Cabana_Grid_SparseHalo.hpp:66
void collectNeighborCounting(MPI_Comm comm, const bool is_neighbor_counting_collected=false) const
neighbor tile counting, communication needed only if the counting is non-zero
Definition Cabana_Grid_SparseHalo.hpp:414
void scatterValidSendAndRecvRanks(MPI_Comm comm, std::vector< int > &valid_sends, std::vector< int > &valid_recvs, const bool is_neighbor_counting_collected=false) const
collect all valid ranks for sparse grid scatter operations
Definition Cabana_Grid_SparseHalo.hpp:467
static constexpr std::size_t num_space_dim
sparse array dimension number
Definition Cabana_Grid_SparseHalo.hpp:55
void unpackBuffer(const ReduceOp &reduce_op, const ExecSpace &exec_space, const buffer_view &buffer, const steering_view &tile_steering, const SparseArrayType &sparse_array, SparseMapType &map, const int count) const
Unpack a sparse array communication buffer.
Definition Cabana_Grid_SparseHalo.hpp:1147
void buildCommData(DecompositionTag decomposition_tag, const std::shared_ptr< LocalGridType > &local_grid, const std::array< int, num_space_dim > &nid, std::vector< buffer_view > &buffers, std::vector< steering_view > &steering, std::vector< tile_index_space > &spaces)
Build communication data.
Definition Cabana_Grid_SparseHalo.hpp:228
Cabana::Tuple< aosoa_member_types > tuple_type
AoSoA tuple type.
Definition Cabana_Grid_SparseHalo.hpp:78
Kokkos::View< tuple_type *, memory_space > buffer_view
communication data buffer view type
Definition Cabana_Grid_SparseHalo.hpp:94
static KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t< 1==M, void > unpackTupleMember(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const Kokkos::Array< std::size_t, M > &extents, const std::integral_constant< std::size_t, N >, const std::integral_constant< std::size_t, M >)
Unpack a sparse arrays element (a tuple) in a buffer (for case tuple members with rank == 1)
Definition Cabana_Grid_SparseHalo.hpp:1033
static KOKKOS_FORCEINLINE_FUNCTION void unpackTuple(const ReduceOp &reduce_op, const tuple_type &src_tuple, SoAType &dst_soa, const int soa_idx, const std::integral_constant< std::size_t, N >)
Unpack a sparse arrays tuple for all members when element ID!=0.
Definition Cabana_Grid_SparseHalo.hpp:1106
TileIndexSpace< num_space_dim, cell_bits_per_tile_dim > tile_index_space
tile index space type TODO
Definition Cabana_Grid_SparseHalo.hpp:99
MemorySpace memory_space
memory space to store the sparse grid
Definition Cabana_Grid_SparseHalo.hpp:58
static KOKKOS_INLINE_FUNCTION void unpackOp(ScatterReduce::Max, const T &buffer_val, T &array_val)
Reduce an element into the buffer. Max reduction.
Definition Cabana_Grid_SparseHalo.hpp:943
static constexpr unsigned long long cell_num_per_tile
sparse grid hierarchy: cell # per dimension
Definition Cabana_Grid_SparseHalo.hpp:90
static constexpr unsigned long long cell_bits_per_tile_dim
sparse grid hierarchy: cell id bit# per dimension
Definition Cabana_Grid_SparseHalo.hpp:87
Definition Cabana_Grid_Halo.hpp:76
Index space with tile as unit; _min and _max forms the tile range. Note this is for sparse grid only,...
Definition Cabana_Grid_SparseIndexSpace.hpp:1137
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
KOKKOS_FORCEINLINE_FUNCTION std::enable_if< is_parameter_pack< ParameterPack_t >::value, typenameParameterPack_t::templatevalue_type< N > & >::type get(ParameterPack_t &pp)
Get an element from a parameter pack.
Definition Cabana_ParameterPack.hpp:129
Ghosted decomposition tag.
Definition Cabana_Grid_Types.hpp:197
Owned decomposition tag.
Definition Cabana_Grid_Types.hpp:190
Definition Cabana_Grid_Halo.hpp:173
Definition Cabana_Grid_Halo.hpp:167
Definition Cabana_Grid_Halo.hpp:181
Sum values from neighboring ranks into this rank's data.
Definition Cabana_Grid_Halo.hpp:161
Get the type of the member at a given index.
Definition Cabana_MemberTypes.hpp:75
Definition Cabana_Tuple.hpp:32