Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_Sort.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_SORT_HPP
17#define CABANA_SORT_HPP
18
19#include <Cabana_AoSoA.hpp>
20#include <Cabana_DeepCopy.hpp>
21#include <Cabana_Slice.hpp>
22#include <Cabana_Utils.hpp>
23
24#include <Kokkos_Core.hpp>
25#include <Kokkos_Profiling_ScopedRegion.hpp>
26#include <Kokkos_Sort.hpp>
27
28#include <type_traits>
29
30namespace Cabana
31{
32//---------------------------------------------------------------------------//
37template <class MemorySpace>
39{
40 public:
42 using memory_space = MemorySpace;
43 static_assert( Kokkos::is_memory_space<MemorySpace>() );
44
46 using execution_space = typename memory_space::execution_space;
48 using size_type = typename memory_space::size_type;
50 using CountView = Kokkos::View<const int*, memory_space>;
52 using OffsetView = Kokkos::View<size_type*, memory_space>;
53
56 : _nbin( 0 )
57 {
58 }
59
69 BinningData( const std::size_t begin, const std::size_t end,
70 CountView counts, OffsetView offsets,
71 OffsetView permute_vector )
72 : _begin( begin )
73 , _end( end )
74 , _nbin( counts.extent( 0 ) )
75 , _counts( counts )
76 , _offsets( offsets )
77 , _permute_vector( permute_vector )
78 {
79 }
80
85 KOKKOS_INLINE_FUNCTION
86 int numBin() const { return _nbin; }
87
93 KOKKOS_INLINE_FUNCTION
94 int binSize( const size_type bin_id ) const { return _counts( bin_id ); }
95
101 KOKKOS_INLINE_FUNCTION
102 size_type binOffset( const size_type bin_id ) const
103 {
104 return _offsets( bin_id );
105 }
106
111 KOKKOS_INLINE_FUNCTION
112 size_type permutation( const size_type tuple_id ) const
113 {
114 return _permute_vector( tuple_id );
115 }
116
120 KOKKOS_INLINE_FUNCTION
121 std::size_t rangeBegin() const { return _begin; }
122
126 KOKKOS_INLINE_FUNCTION
127 std::size_t rangeEnd() const { return _end; }
128
129 private:
130 std::size_t _begin;
131 std::size_t _end;
132 int _nbin;
133 CountView _counts;
134 OffsetView _offsets;
135 OffsetView _permute_vector;
136};
137
138//---------------------------------------------------------------------------//
140template <typename>
141struct is_binning_data : public std::false_type
142{
143};
144
145template <typename MemorySpace>
146struct is_binning_data<BinningData<MemorySpace>> : public std::true_type
147{
148};
150
152template <typename MemorySpace>
153struct is_binning_data<const BinningData<MemorySpace>> : public std::true_type
154{
155};
156
157namespace Impl
158{
159//---------------------------------------------------------------------------//
162template <class KeyViewType, class Comparator,
163 class ExecutionSpace = typename KeyViewType::execution_space>
164auto kokkosBinSort( KeyViewType keys, Comparator comp,
165 const bool sort_within_bins, const std::size_t begin,
166 const std::size_t end )
167{
168 Kokkos::Profiling::ScopedRegion region( "Cabana::BinSort" );
169 using memory_space = typename KeyViewType::memory_space;
171
172 Kokkos::BinSort<KeyViewType, Comparator> bin_sort( keys, begin, end, comp,
173 sort_within_bins );
174 bin_sort.create_permute_vector();
175
176 return BinningData<memory_space>( begin, end, bin_sort.get_bin_count(),
177 bin_sort.get_bin_offsets(),
178 bin_sort.get_permute_vector() );
179}
180
181//---------------------------------------------------------------------------//
183template <class KeyViewType,
184 class ExecutionSpace = typename KeyViewType::execution_space>
185Kokkos::MinMaxScalar<typename KeyViewType::non_const_value_type>
186keyMinMax( KeyViewType keys, const std::size_t begin, const std::size_t end )
187{
188 Kokkos::Profiling::ScopedRegion region( "Cabana::keyMinMax" );
189
190 using memory_space = typename KeyViewType::memory_space;
192
193 using KeyValueType = typename KeyViewType::non_const_value_type;
194 Kokkos::MinMaxScalar<KeyValueType> result;
195 Kokkos::MinMax<KeyValueType> reducer( result );
196 Kokkos::parallel_reduce(
197 "Cabana::keyMinMax", Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
198 KOKKOS_LAMBDA( std::size_t i, decltype( result )& local_minmax ) {
199 auto const val = keys( i );
200 if ( val < local_minmax.min_val )
201 {
202 local_minmax.min_val = val;
203 }
204 if ( val > local_minmax.max_val )
205 {
206 local_minmax.max_val = val;
207 }
208 },
209 reducer );
210 Kokkos::fence();
211
212 return result;
213}
214
215//---------------------------------------------------------------------------//
218template <class KeyViewType,
219 class ExecutionSpace = typename KeyViewType::execution_space>
220auto kokkosBinSort1d( KeyViewType keys, const int nbin,
221 const bool sort_within_bins, const std::size_t begin,
222 const std::size_t end )
223{
224 // Find the minimum and maximum key values.
225 auto key_bounds =
227
228 // Create a sorting comparator.
229 Kokkos::BinOp1D<KeyViewType> comp( nbin, key_bounds.min_val,
230 key_bounds.max_val );
231
232 // BinSort
234 keys, comp, sort_within_bins, begin, end );
235}
236
237//---------------------------------------------------------------------------//
238
239} // end namespace Impl
240
241//---------------------------------------------------------------------------//
257template <class KeyViewType, class Comparator,
258 class ExecutionSpace = typename KeyViewType::execution_space>
260 KeyViewType keys, Comparator comp, const std::size_t begin,
261 const std::size_t end,
262 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
263 int>::type* = 0 )
264{
266 keys, comp, true, begin, end );
267 return bin_data.permuteVector();
268}
269
270//---------------------------------------------------------------------------//
284template <class KeyViewType, class Comparator,
285 class ExecutionSpace = typename KeyViewType::execution_space>
287 KeyViewType keys, Comparator comp,
288 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
289 int>::type* = 0 )
290{
292 keys.extent( 0 ) );
293}
294
295//---------------------------------------------------------------------------//
311template <class KeyViewType, class Comparator,
312 class ExecutionSpace = typename KeyViewType::execution_space>
314 KeyViewType keys, Comparator comp, const std::size_t begin,
315 const std::size_t end,
316 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
317 int>::type* = 0 )
318{
319 return Impl::kokkosBinSort<KeyViewType, ExecutionSpace>( keys, comp, false,
320 begin, end );
321}
322
323//---------------------------------------------------------------------------//
340template <class KeyViewType, class Comparator,
341 class ExecutionSpace = typename KeyViewType::execution_space>
343 KeyViewType keys, Comparator comp,
344 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
345 int>::type* = 0 )
346{
348 keys, comp, false, 0, keys.extent( 0 ) );
349}
350
351//---------------------------------------------------------------------------//
364template <class KeyViewType,
365 class ExecutionSpace = typename KeyViewType::execution_space>
366auto sortByKey( KeyViewType keys, const std::size_t begin,
367 const std::size_t end,
368 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
369 int>::type* = 0 )
370{
371 int nbin = ( end - begin ) / 2;
373 begin, end );
374}
375
376//---------------------------------------------------------------------------//
386template <class KeyViewType,
387 class ExecutionSpace = typename KeyViewType::execution_space>
388auto sortByKey( KeyViewType keys,
389 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
390 int>::type* = 0 )
391{
392 return sortByKey<KeyViewType, ExecutionSpace>( keys, 0, keys.extent( 0 ) );
393}
394
395//---------------------------------------------------------------------------//
411template <class KeyViewType,
412 class ExecutionSpace = typename KeyViewType::execution_space>
413auto binByKey( KeyViewType keys, const int nbin, const std::size_t begin,
414 const std::size_t end,
415 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
416 int>::type* = 0 )
417{
419 keys, nbin, false, begin, end );
420}
421
422//---------------------------------------------------------------------------//
435template <class KeyViewType,
436 class ExecutionSpace = typename KeyViewType::execution_space>
437auto binByKey( KeyViewType keys, const int nbin,
438 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
439 int>::type* = 0 )
440{
442 keys, nbin, false, 0, keys.extent( 0 ) );
443}
444
445//---------------------------------------------------------------------------//
457template <class SliceType,
458 class ExecutionSpace = typename SliceType::execution_space>
460 SliceType slice, const std::size_t begin, const std::size_t end,
461 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
462{
463 Kokkos::View<typename SliceType::value_type*,
464 typename SliceType::memory_space>
465 keys( Kokkos::ViewAllocateWithoutInitializing( "slice_keys" ),
466 slice.size() );
467
468 copySliceToView( keys, slice, 0, slice.size() );
469 return sortByKey<decltype( keys ), ExecutionSpace>( keys, begin, end );
470}
471
472//---------------------------------------------------------------------------//
481template <class SliceType,
482 class ExecutionSpace = typename SliceType::execution_space>
484 SliceType slice,
485 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
486{
488}
489
490//---------------------------------------------------------------------------//
504template <class SliceType,
505 class ExecutionSpace = typename SliceType::execution_space>
507 SliceType slice, const int nbin, const std::size_t begin,
508 const std::size_t end,
509 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
510{
511 Kokkos::View<typename SliceType::value_type*,
512 typename SliceType::memory_space>
513 keys( Kokkos::ViewAllocateWithoutInitializing( "slice_keys" ),
514 slice.size() );
515
516 copySliceToView( keys, slice, 0, slice.size() );
517 return binByKey<decltype( keys ), ExecutionSpace>( keys, nbin, begin, end );
518}
519
520//---------------------------------------------------------------------------//
531template <class SliceType,
532 class ExecutionSpace = typename SliceType::execution_space>
534 SliceType slice, const int nbin,
535 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
536{
537 return binByKey<SliceType, ExecutionSpace>( slice, nbin, 0, slice.size() );
538}
539
540//---------------------------------------------------------------------------//
549template <class BinningDataType, class AoSoA_t,
550 class ExecutionSpace = typename BinningDataType::execution_space>
552 const BinningDataType& binning_data, AoSoA_t& aosoa,
553 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
555 int>::type* = 0 )
556{
557 Kokkos::Profiling::ScopedRegion region( "Cabana::permute" );
558
559 using memory_space = typename BinningDataType::memory_space;
561
562 auto begin = binning_data.rangeBegin();
563 auto end = binning_data.rangeEnd();
564
565 using memory_space = typename BinningDataType::memory_space;
566 Kokkos::View<typename AoSoA_t::tuple_type*, memory_space> scratch_tuples(
567 Kokkos::ViewAllocateWithoutInitializing( "scratch_tuples" ),
568 end - begin );
569
570 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
571 {
572 scratch_tuples( i - begin ) =
573 aosoa.getTuple( binning_data.permutation( i - begin ) );
574 };
575 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch",
576 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
577 permute_to_scratch );
578 Kokkos::fence();
579
580 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
581 {
582 aosoa.setTuple( i, scratch_tuples( i - begin ) );
583 };
584 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back",
585 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
586 copy_back );
587 Kokkos::fence();
588}
589
590//---------------------------------------------------------------------------//
600template <class BinningDataType, class SliceType,
601 class ExecutionSpace = typename BinningDataType::execution_space>
603 const BinningDataType& binning_data, SliceType& slice,
604 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
606 int>::type* = 0 )
607{
608 Kokkos::Profiling::ScopedRegion region( "Cabana::permute" );
609
610 using memory_space = typename BinningDataType::memory_space;
612
613 auto begin = binning_data.rangeBegin();
614 auto end = binning_data.rangeEnd();
615
616 // Get the number of components in the slice.
617 std::size_t num_comp = 1;
618 for ( std::size_t d = 2; d < slice.viewRank(); ++d )
619 num_comp *= slice.extent( d );
620
621 // Get the raw slice data.
622 auto slice_data = slice.data();
623
624 Kokkos::View<typename SliceType::value_type**, memory_space> scratch_array(
625 Kokkos::ViewAllocateWithoutInitializing( "scratch_array" ), end - begin,
626 num_comp );
627
628 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
629 {
630 auto permute_i = binning_data.permutation( i - begin );
631 auto s = SliceType::index_type::s( permute_i );
632 auto a = SliceType::index_type::a( permute_i );
633 std::size_t slice_offset = s * slice.stride( 0 ) + a;
634 for ( std::size_t n = 0; n < num_comp; ++n )
635 scratch_array( i - begin, n ) =
636 slice_data[slice_offset + SliceType::vector_length * n];
637 };
638 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch",
639 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
640 permute_to_scratch );
641 Kokkos::fence();
642
643 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
644 {
645 auto s = SliceType::index_type::s( i );
646 auto a = SliceType::index_type::a( i );
647 std::size_t slice_offset = s * slice.stride( 0 ) + a;
648 for ( std::size_t n = 0; n < num_comp; ++n )
649 slice_data[slice_offset + SliceType::vector_length * n] =
650 scratch_array( i - begin, n );
651 };
652 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back",
653 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
654 copy_back );
655 Kokkos::fence();
656}
657
658//---------------------------------------------------------------------------//
670template <class BinningDataType, class ViewType,
671 class MemorySpace = typename BinningDataType::memory_space>
673 const BinningDataType& binning_data, ViewType& view,
674 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
675 Kokkos::is_view<ViewType>::value ),
676 int>::type* = 0 )
677{
678 Kokkos::Profiling::pushRegion( "Cabana::permute" );
679
680 auto begin = binning_data.rangeBegin();
681 auto end = binning_data.rangeEnd();
682
683 // Get the number of components (1 for View).
684 std::size_t num_comp = 1;
685 for ( std::size_t d = 1; d < view.rank; ++d )
686 num_comp *= view.extent( d );
687
688 Kokkos::View<typename ViewType::value_type**, MemorySpace> scratch(
689 Kokkos::ViewAllocateWithoutInitializing( "scratch" ), end - begin,
690 num_comp );
691
692 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
693 {
694 auto permute_i = binning_data.permutation( i - begin );
695 for ( std::size_t n = 0; n < num_comp; ++n )
696 scratch( i - begin, n ) = view( permute_i, n );
697 };
698 auto policy =
699 Kokkos::RangePolicy<typename BinningDataType::execution_space>( begin,
700 end );
701 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch", policy,
702 permute_to_scratch );
703 Kokkos::fence();
704
705 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
706 {
707 for ( std::size_t n = 0; n < num_comp; ++n )
708 view( i, n ) = scratch( i - begin, n );
709 };
710 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back", policy,
711 copy_back );
712 Kokkos::fence();
713
714 Kokkos::Profiling::popRegion();
715}
716
717//---------------------------------------------------------------------------//
718
719} // end namespace Cabana
720
721#endif // end CABANA_SORT_HPP
Array-of-Struct-of-Arrays particle data structure.
AoSoA and slice extensions for Kokkos deep copy and mirrors.
Slice a single particle property from an AoSoA.
auto kokkosBinSort(KeyViewType keys, Comparator comp, const bool sort_within_bins, const std::size_t begin, const std::size_t end)
Definition Cabana_Sort.hpp:164
auto kokkosBinSort1d(KeyViewType keys, const int nbin, const bool sort_within_bins, const std::size_t begin, const std::size_t end)
Definition Cabana_Sort.hpp:220
Kokkos::MinMaxScalar< typename KeyViewType::non_const_value_type > keyMinMax(KeyViewType keys, const std::size_t begin, const std::size_t end)
Given a set of keys, find the minimum and maximum over the given range.
Definition Cabana_Sort.hpp:186
Cabana utilities.
Data describing the bin sizes and offsets resulting from a binning operation.
Definition Cabana_Sort.hpp:39
KOKKOS_INLINE_FUNCTION size_type binOffset(const size_type bin_id) const
Given a bin get the tuple index at which it sorts.
Definition Cabana_Sort.hpp:102
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Sort.hpp:42
Kokkos::View< const int *, memory_space > CountView
Binning view type.
Definition Cabana_Sort.hpp:50
BinningData()
Default constructor.
Definition Cabana_Sort.hpp:55
typename memory_space::execution_space execution_space
Default execution space.
Definition Cabana_Sort.hpp:46
KOKKOS_INLINE_FUNCTION int binSize(const size_type bin_id) const
Given a bin get the number of tuples it contains.
Definition Cabana_Sort.hpp:94
KOKKOS_INLINE_FUNCTION std::size_t rangeBegin() const
The beginning tuple index in the binning.
Definition Cabana_Sort.hpp:121
KOKKOS_INLINE_FUNCTION std::size_t rangeEnd() const
The ending tuple index in the binning.
Definition Cabana_Sort.hpp:127
KOKKOS_INLINE_FUNCTION size_type permutation(const size_type tuple_id) const
Given a local tuple id in the binned layout, get the id of the tuple in the old (unbinned) layout.
Definition Cabana_Sort.hpp:112
Kokkos::View< size_type *, memory_space > OffsetView
Offset view type.
Definition Cabana_Sort.hpp:52
typename memory_space::size_type size_type
Memory space size type.
Definition Cabana_Sort.hpp:48
KOKKOS_INLINE_FUNCTION int numBin() const
Get the number of bins.
Definition Cabana_Sort.hpp:86
BinningData(const std::size_t begin, const std::size_t end, CountView counts, OffsetView offsets, OffsetView permute_vector)
Constructor initializing from Kokkos BinSort data.
Definition Cabana_Sort.hpp:69
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
auto binByKey(KeyViewType keys, const int nbin, const std::size_t begin, const std::size_t end, typename std::enable_if<(Kokkos::is_view< KeyViewType >::value), int >::type *=0)
Bin an AoSoA over a subset of its range based on the associated key values and number of bins....
Definition Cabana_Sort.hpp:413
void copySliceToView(ExecutionSpace exec_space, ViewType &view, const SliceType &slice, const std::size_t begin, const std::size_t end, typename std::enable_if< 2==SliceType::kokkos_view::traits::dimension::rank, int * >::type=0)
Copy from slice to View. Rank-0.
Definition Cabana_Slice.hpp:877
auto sortByKey(KeyViewType keys, const std::size_t begin, const std::size_t end, typename std::enable_if<(Kokkos::is_view< KeyViewType >::value), int >::type *=0)
Sort an AoSoA over a subset of its range based on the associated key values.
Definition Cabana_Sort.hpp:366
void permute(LinkedCellListType &linked_cell_list, PositionType &positions, typename std::enable_if<(is_linked_cell_list< LinkedCellListType >::value &&(is_aosoa< PositionType >::value||is_slice< PositionType >::value||Kokkos::is_view< PositionType >::value)), int >::type *=0)
Given a linked cell list permute positions.
Definition Cabana_LinkedCellList.hpp:730
AoSoA_t::template member_slice_type< M > slice(const AoSoA_t &aosoa, const std::string &slice_label="")
Create a slice from an AoSoA.
Definition Cabana_AoSoA.hpp:77
auto sortByKeyWithComparator(KeyViewType keys, Comparator comp, const std::size_t begin, const std::size_t end, typename std::enable_if<(Kokkos::is_view< KeyViewType >::value), int >::type *=0)
Sort an AoSoA over a subset of its range using a general comparator over the given Kokkos View of key...
Definition Cabana_Sort.hpp:259
auto binByKeyWithComparator(KeyViewType keys, Comparator comp, const std::size_t begin, const std::size_t end, typename std::enable_if<(Kokkos::is_view< KeyViewType >::value), int >::type *=0)
Bin an AoSoA over a subset of its range using a general comparator over the given Kokkos View of keys...
Definition Cabana_Sort.hpp:313
Definition Cabana_Types.hpp:88
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:868