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:
41 // FIXME: extracting the self type for backwards compatibility with previous
42 // template on DeviceType. Should simply be MemorySpace after next release.
44 using memory_space = typename MemorySpace::memory_space;
45 // FIXME: replace warning with memory space assert after next release.
46 static_assert( Impl::deprecated( Kokkos::is_device<MemorySpace>() ) );
47
49 using device_type [[deprecated]] = typename memory_space::device_type;
51 using execution_space = typename memory_space::execution_space;
53 using size_type = typename memory_space::size_type;
55 using CountView = Kokkos::View<const int*, memory_space>;
57 using OffsetView = Kokkos::View<size_type*, memory_space>;
58
61 : _nbin( 0 )
62 {
63 }
64
74 BinningData( const std::size_t begin, const std::size_t end,
75 CountView counts, OffsetView offsets,
76 OffsetView permute_vector )
77 : _begin( begin )
78 , _end( end )
79 , _nbin( counts.extent( 0 ) )
80 , _counts( counts )
81 , _offsets( offsets )
82 , _permute_vector( permute_vector )
83 {
84 }
85
90 KOKKOS_INLINE_FUNCTION
91 int numBin() const { return _nbin; }
92
98 KOKKOS_INLINE_FUNCTION
99 int binSize( const size_type bin_id ) const { return _counts( bin_id ); }
100
106 KOKKOS_INLINE_FUNCTION
107 size_type binOffset( const size_type bin_id ) const
108 {
109 return _offsets( bin_id );
110 }
111
116 KOKKOS_INLINE_FUNCTION
117 size_type permutation( const size_type tuple_id ) const
118 {
119 return _permute_vector( tuple_id );
120 }
121
125 KOKKOS_INLINE_FUNCTION
126 std::size_t rangeBegin() const { return _begin; }
127
131 KOKKOS_INLINE_FUNCTION
132 std::size_t rangeEnd() const { return _end; }
133
134 private:
135 std::size_t _begin;
136 std::size_t _end;
137 int _nbin;
138 CountView _counts;
139 OffsetView _offsets;
140 OffsetView _permute_vector;
141};
142
143//---------------------------------------------------------------------------//
145template <typename>
146struct is_binning_data : public std::false_type
147{
148};
149
150template <typename MemorySpace>
151struct is_binning_data<BinningData<MemorySpace>> : public std::true_type
152{
153};
155
157template <typename MemorySpace>
158struct is_binning_data<const BinningData<MemorySpace>> : public std::true_type
159{
160};
161
162namespace Impl
163{
164//---------------------------------------------------------------------------//
167template <class KeyViewType, class Comparator,
168 class ExecutionSpace = typename KeyViewType::execution_space>
169auto kokkosBinSort( KeyViewType keys, Comparator comp,
170 const bool sort_within_bins, const std::size_t begin,
171 const std::size_t end )
172{
173 Kokkos::Profiling::ScopedRegion region( "Cabana::BinSort" );
174 using memory_space = typename KeyViewType::memory_space;
176
177 Kokkos::BinSort<KeyViewType, Comparator> bin_sort( keys, begin, end, comp,
178 sort_within_bins );
179 bin_sort.create_permute_vector();
180
181 return BinningData<memory_space>( begin, end, bin_sort.get_bin_count(),
182 bin_sort.get_bin_offsets(),
183 bin_sort.get_permute_vector() );
184}
185
186//---------------------------------------------------------------------------//
188template <class KeyViewType,
189 class ExecutionSpace = typename KeyViewType::execution_space>
190Kokkos::MinMaxScalar<typename KeyViewType::non_const_value_type>
191keyMinMax( KeyViewType keys, const std::size_t begin, const std::size_t end )
192{
193 Kokkos::Profiling::ScopedRegion region( "Cabana::keyMinMax" );
194
195 using memory_space = typename KeyViewType::memory_space;
197
198 using KeyValueType = typename KeyViewType::non_const_value_type;
199 Kokkos::MinMaxScalar<KeyValueType> result;
200 Kokkos::MinMax<KeyValueType> reducer( result );
201 Kokkos::parallel_reduce(
202 "Cabana::keyMinMax", Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
203 KOKKOS_LAMBDA( std::size_t i, decltype( result )& local_minmax ) {
204 auto const val = keys( i );
205 if ( val < local_minmax.min_val )
206 {
207 local_minmax.min_val = val;
208 }
209 if ( val > local_minmax.max_val )
210 {
211 local_minmax.max_val = val;
212 }
213 },
214 reducer );
215 Kokkos::fence();
216
217 return result;
218}
219
220//---------------------------------------------------------------------------//
223template <class KeyViewType,
224 class ExecutionSpace = typename KeyViewType::execution_space>
225auto kokkosBinSort1d( KeyViewType keys, const int nbin,
226 const bool sort_within_bins, const std::size_t begin,
227 const std::size_t end )
228{
229 // Find the minimum and maximum key values.
230 auto key_bounds =
232
233 // Create a sorting comparator.
234 Kokkos::BinOp1D<KeyViewType> comp( nbin, key_bounds.min_val,
235 key_bounds.max_val );
236
237 // BinSort
239 keys, comp, sort_within_bins, begin, end );
240}
241
242//---------------------------------------------------------------------------//
243
244} // end namespace Impl
245
246//---------------------------------------------------------------------------//
262template <class KeyViewType, class Comparator,
263 class ExecutionSpace = typename KeyViewType::execution_space>
265 KeyViewType keys, Comparator comp, const std::size_t begin,
266 const std::size_t end,
267 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
268 int>::type* = 0 )
269{
271 keys, comp, true, begin, end );
272 return bin_data.permuteVector();
273}
274
275//---------------------------------------------------------------------------//
289template <class KeyViewType, class Comparator,
290 class ExecutionSpace = typename KeyViewType::execution_space>
292 KeyViewType keys, Comparator comp,
293 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
294 int>::type* = 0 )
295{
297 keys.extent( 0 ) );
298}
299
300//---------------------------------------------------------------------------//
316template <class KeyViewType, class Comparator,
317 class ExecutionSpace = typename KeyViewType::execution_space>
319 KeyViewType keys, Comparator comp, const std::size_t begin,
320 const std::size_t end,
321 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
322 int>::type* = 0 )
323{
324 return Impl::kokkosBinSort<KeyViewType, ExecutionSpace>( keys, comp, false,
325 begin, end );
326}
327
328//---------------------------------------------------------------------------//
345template <class KeyViewType, class Comparator,
346 class ExecutionSpace = typename KeyViewType::execution_space>
348 KeyViewType keys, Comparator comp,
349 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
350 int>::type* = 0 )
351{
353 keys, comp, false, 0, keys.extent( 0 ) );
354}
355
356//---------------------------------------------------------------------------//
369template <class KeyViewType,
370 class ExecutionSpace = typename KeyViewType::execution_space>
371auto sortByKey( KeyViewType keys, const std::size_t begin,
372 const std::size_t end,
373 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
374 int>::type* = 0 )
375{
376 int nbin = ( end - begin ) / 2;
378 begin, end );
379}
380
381//---------------------------------------------------------------------------//
391template <class KeyViewType,
392 class ExecutionSpace = typename KeyViewType::execution_space>
393auto sortByKey( KeyViewType keys,
394 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
395 int>::type* = 0 )
396{
397 return sortByKey<KeyViewType, ExecutionSpace>( keys, 0, keys.extent( 0 ) );
398}
399
400//---------------------------------------------------------------------------//
416template <class KeyViewType,
417 class ExecutionSpace = typename KeyViewType::execution_space>
418auto binByKey( KeyViewType keys, const int nbin, const std::size_t begin,
419 const std::size_t end,
420 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
421 int>::type* = 0 )
422{
424 keys, nbin, false, begin, end );
425}
426
427//---------------------------------------------------------------------------//
440template <class KeyViewType,
441 class ExecutionSpace = typename KeyViewType::execution_space>
442auto binByKey( KeyViewType keys, const int nbin,
443 typename std::enable_if<( Kokkos::is_view<KeyViewType>::value ),
444 int>::type* = 0 )
445{
447 keys, nbin, false, 0, keys.extent( 0 ) );
448}
449
450//---------------------------------------------------------------------------//
462template <class SliceType,
463 class ExecutionSpace = typename SliceType::execution_space>
465 SliceType slice, const std::size_t begin, const std::size_t end,
466 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
467{
468 Kokkos::View<typename SliceType::value_type*,
469 typename SliceType::memory_space>
470 keys( Kokkos::ViewAllocateWithoutInitializing( "slice_keys" ),
471 slice.size() );
472
473 copySliceToView( keys, slice, 0, slice.size() );
474 return sortByKey<decltype( keys ), ExecutionSpace>( keys, begin, end );
475}
476
477//---------------------------------------------------------------------------//
486template <class SliceType,
487 class ExecutionSpace = typename SliceType::execution_space>
489 SliceType slice,
490 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
491{
493}
494
495//---------------------------------------------------------------------------//
509template <class SliceType,
510 class ExecutionSpace = typename SliceType::execution_space>
512 SliceType slice, const int nbin, const std::size_t begin,
513 const std::size_t end,
514 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
515{
516 Kokkos::View<typename SliceType::value_type*,
517 typename SliceType::memory_space>
518 keys( Kokkos::ViewAllocateWithoutInitializing( "slice_keys" ),
519 slice.size() );
520
521 copySliceToView( keys, slice, 0, slice.size() );
522 return binByKey<decltype( keys ), ExecutionSpace>( keys, nbin, begin, end );
523}
524
525//---------------------------------------------------------------------------//
536template <class SliceType,
537 class ExecutionSpace = typename SliceType::execution_space>
539 SliceType slice, const int nbin,
540 typename std::enable_if<( is_slice<SliceType>::value ), int>::type* = 0 )
541{
542 return binByKey<SliceType, ExecutionSpace>( slice, nbin, 0, slice.size() );
543}
544
545//---------------------------------------------------------------------------//
554template <class BinningDataType, class AoSoA_t,
555 class ExecutionSpace = typename BinningDataType::execution_space>
557 const BinningDataType& binning_data, AoSoA_t& aosoa,
558 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
560 int>::type* = 0 )
561{
562 Kokkos::Profiling::ScopedRegion region( "Cabana::permute" );
563
564 using memory_space = typename BinningDataType::memory_space;
566
567 auto begin = binning_data.rangeBegin();
568 auto end = binning_data.rangeEnd();
569
570 using memory_space = typename BinningDataType::memory_space;
571 Kokkos::View<typename AoSoA_t::tuple_type*, memory_space> scratch_tuples(
572 Kokkos::ViewAllocateWithoutInitializing( "scratch_tuples" ),
573 end - begin );
574
575 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
576 {
577 scratch_tuples( i - begin ) =
578 aosoa.getTuple( binning_data.permutation( i - begin ) );
579 };
580 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch",
581 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
582 permute_to_scratch );
583 Kokkos::fence();
584
585 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
586 {
587 aosoa.setTuple( i, scratch_tuples( i - begin ) );
588 };
589 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back",
590 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
591 copy_back );
592 Kokkos::fence();
593}
594
595//---------------------------------------------------------------------------//
605template <class BinningDataType, class SliceType,
606 class ExecutionSpace = typename BinningDataType::execution_space>
608 const BinningDataType& binning_data, SliceType& slice,
609 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
611 int>::type* = 0 )
612{
613 Kokkos::Profiling::ScopedRegion region( "Cabana::permute" );
614
615 using memory_space = typename BinningDataType::memory_space;
617
618 auto begin = binning_data.rangeBegin();
619 auto end = binning_data.rangeEnd();
620
621 // Get the number of components in the slice.
622 std::size_t num_comp = 1;
623 for ( std::size_t d = 2; d < slice.viewRank(); ++d )
624 num_comp *= slice.extent( d );
625
626 // Get the raw slice data.
627 auto slice_data = slice.data();
628
629 Kokkos::View<typename SliceType::value_type**, memory_space> scratch_array(
630 Kokkos::ViewAllocateWithoutInitializing( "scratch_array" ), end - begin,
631 num_comp );
632
633 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
634 {
635 auto permute_i = binning_data.permutation( i - begin );
636 auto s = SliceType::index_type::s( permute_i );
637 auto a = SliceType::index_type::a( permute_i );
638 std::size_t slice_offset = s * slice.stride( 0 ) + a;
639 for ( std::size_t n = 0; n < num_comp; ++n )
640 scratch_array( i - begin, n ) =
641 slice_data[slice_offset + SliceType::vector_length * n];
642 };
643 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch",
644 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
645 permute_to_scratch );
646 Kokkos::fence();
647
648 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
649 {
650 auto s = SliceType::index_type::s( i );
651 auto a = SliceType::index_type::a( i );
652 std::size_t slice_offset = s * slice.stride( 0 ) + a;
653 for ( std::size_t n = 0; n < num_comp; ++n )
654 slice_data[slice_offset + SliceType::vector_length * n] =
655 scratch_array( i - begin, n );
656 };
657 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back",
658 Kokkos::RangePolicy<ExecutionSpace>( begin, end ),
659 copy_back );
660 Kokkos::fence();
661}
662
663//---------------------------------------------------------------------------//
675template <class BinningDataType, class ViewType,
676 class DeviceType = typename BinningDataType::device_type>
678 const BinningDataType& binning_data, ViewType& view,
679 typename std::enable_if<( is_binning_data<BinningDataType>::value &&
680 Kokkos::is_view<ViewType>::value ),
681 int>::type* = 0 )
682{
683 Kokkos::Profiling::pushRegion( "Cabana::permute" );
684
685 auto begin = binning_data.rangeBegin();
686 auto end = binning_data.rangeEnd();
687
688 // Get the number of components (1 for View).
689 std::size_t num_comp = 1;
690 for ( std::size_t d = 1; d < view.rank; ++d )
691 num_comp *= view.extent( d );
692
693 Kokkos::View<typename ViewType::value_type**, DeviceType> scratch(
694 Kokkos::ViewAllocateWithoutInitializing( "scratch" ), end - begin,
695 num_comp );
696
697 auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i )
698 {
699 auto permute_i = binning_data.permutation( i - begin );
700 for ( std::size_t n = 0; n < num_comp; ++n )
701 scratch( i - begin, n ) = view( permute_i, n );
702 };
703 auto policy =
704 Kokkos::RangePolicy<typename DeviceType::execution_space>( begin, end );
705 Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch", policy,
706 permute_to_scratch );
707 Kokkos::fence();
708
709 auto copy_back = KOKKOS_LAMBDA( const std::size_t i )
710 {
711 for ( std::size_t n = 0; n < num_comp; ++n )
712 view( i, n ) = scratch( i - begin, n );
713 };
714 Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back", policy,
715 copy_back );
716 Kokkos::fence();
717
718 Kokkos::Profiling::popRegion();
719}
720
721//---------------------------------------------------------------------------//
722
723} // end namespace Cabana
724
725#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:169
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:225
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:191
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:107
Kokkos::View< const int *, memory_space > CountView
Binning view type.
Definition Cabana_Sort.hpp:55
BinningData()
Default constructor.
Definition Cabana_Sort.hpp:60
typename memory_space::execution_space execution_space
Default execution space.
Definition Cabana_Sort.hpp:51
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:99
KOKKOS_INLINE_FUNCTION std::size_t rangeBegin() const
The beginning tuple index in the binning.
Definition Cabana_Sort.hpp:126
KOKKOS_INLINE_FUNCTION std::size_t rangeEnd() const
The ending tuple index in the binning.
Definition Cabana_Sort.hpp:132
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:117
Kokkos::View< size_type *, memory_space > OffsetView
Offset view type.
Definition Cabana_Sort.hpp:57
typename memory_space::size_type size_type
Memory space size type.
Definition Cabana_Sort.hpp:53
KOKKOS_INLINE_FUNCTION int numBin() const
Get the number of bins.
Definition Cabana_Sort.hpp:91
typename MemorySpace::memory_space memory_space
Memory space.
Definition Cabana_Sort.hpp:44
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:74
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:418
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:870
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:371
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:737
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:264
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:318
Definition Cabana_Types.hpp:88
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:861