16#ifndef CABANA_EXPERIMENTAL_NEIGHBOR_LIST_HPP
17#define CABANA_EXPERIMENTAL_NEIGHBOR_LIST_HPP
25#include <Kokkos_Core.hpp>
39 using type = std::remove_cv_t<std::remove_reference_t<T>>;
43using remove_cvref_t =
typename remove_cvref<T>::type;
49template <
typename Positions,
50 typename = std::enable_if_t<Cabana::is_slice<Positions>::value ||
51 Kokkos::is_view_v<Positions>>>
52struct SubPositionsAndRadius
54 using positions_type = Positions;
55 using memory_space =
typename Positions::memory_space;
57 using size_type =
typename Positions::size_type;
60 using value_type =
typename Positions::value_type;
64template <
typename Positions,
65 typename = std::enable_if_t<
66 Cabana::is_slice<std::remove_reference_t<Positions>>::value ||
67 Kokkos::is_view_v<Positions>>>
69 Positions&& positions,
70 typename stdcxx20::remove_cvref_t<Positions>::size_type first,
71 typename stdcxx20::remove_cvref_t<Positions>::size_type last,
72 typename stdcxx20::remove_cvref_t<Positions>::value_type radius )
74 return Impl::SubPositionsAndRadius<stdcxx20::remove_cvref_t<Positions>>{
75 std::forward<Positions>( positions ), first, last, radius };
78template <
typename ExecutionSpace,
typename D,
typename... P>
79typename Kokkos::View<D, P...>::non_const_value_type
80max_reduce( ExecutionSpace
const& space, Kokkos::View<D, P...>
const& v )
82 using V = Kokkos::View<D, P...>;
83 static_assert( V::rank == 1 );
84 static_assert( Kokkos::is_execution_space<ExecutionSpace>::value );
86 is_accessible_from<typename V::memory_space, ExecutionSpace>::value );
87 using Ret =
typename Kokkos::View<D, P...>::non_const_value_type;
89 Kokkos::parallel_reduce(
90 Kokkos::RangePolicy<ExecutionSpace>( space, 0, v.extent( 0 ) ),
91 KOKKOS_LAMBDA(
int i, Ret& partial_max ) {
92 if ( v( i ) > partial_max )
97 Kokkos::Max<Ret>( max_val ) );
108template <
typename Positions>
109struct AccessTraits<Positions,
110#if ARBORX_VERSION < 10799
113 std::enable_if_t<Cabana::is_slice<Positions>{} ||
114 Kokkos::is_view<Positions>{}>>
128 return Point{
static_cast<float>( x( i, 0 ) ),
129 static_cast<float>( x( i, 1 ) ),
130 static_cast<float>( x( i, 2 ) ) };
134template <
typename Positions>
135struct AccessTraits<
Cabana::Experimental::Impl::SubPositionsAndRadius<Positions>
136#if ARBORX_VERSION < 10799
144 Cabana::Experimental::Impl::SubPositionsAndRadius<Positions>;
152 return x.last - x.first;
157 assert( i <
size( x ) );
158 auto const point = AccessTraits<
typename PositionLike::positions_type
159#if ARBORX_VERSION < 10799
163 >
::get( x.data, x.first + i );
165 intersects( Sphere{ point,
static_cast<float>( x.radius ) } ),
173namespace Experimental
179template <
typename Tag>
180struct CollisionFilter;
183struct CollisionFilter<FullNeighborTag>
185 KOKKOS_FUNCTION
bool static keep(
int i,
int j )
noexcept
192struct CollisionFilter<HalfNeighborTag>
194 KOKKOS_FUNCTION
static bool keep(
int i,
int j )
noexcept {
return i > j; }
198template <
typename Tag>
199struct NeighborDiscriminatorCallback
201#if ARBORX_VERSION >= 10799
202 template <
typename Predicate,
typename Geometry,
typename OutputFunctor>
204 operator()( Predicate
const& predicate,
205 ArborX::PairValueIndex<Geometry, int>
const& value_pair,
206 OutputFunctor
const& out )
const
208 int const primitive_index = value_pair.index;
209 int const predicate_index = getData( predicate );
210 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
212 out( primitive_index );
216 template <
typename Predicate,
typename OutputFunctor>
217 KOKKOS_FUNCTION
void operator()( Predicate
const& predicate,
219 OutputFunctor
const& out )
const
221 int const predicate_index = getData( predicate );
222 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
224 out( primitive_index );
231template <
typename Counts,
typename Tag>
232struct NeighborDiscriminatorCallback2D_FirstPass
235#if ARBORX_VERSION >= 10799
236 template <
typename Predicate,
typename Geometry>
238 operator()( Predicate
const& predicate,
239 ArborX::PairValueIndex<Geometry, int>
const& value_pair )
const
241 int const primitive_index = value_pair.index;
242 int const predicate_index = getData( predicate );
243 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
245 ++counts( predicate_index );
249 template <
typename Predicate>
250 KOKKOS_FUNCTION
void operator()( Predicate
const& predicate,
251 int primitive_index )
const
253 int const predicate_index = getData( predicate );
254 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
256 ++counts( predicate_index );
263template <
typename Counts,
typename Neighbors,
typename Tag>
264struct NeighborDiscriminatorCallback2D_FirstPass_BufferOptimization
268#if ARBORX_VERSION >= 10799
269 template <
typename Predicate,
typename Geometry>
271 operator()( Predicate
const& predicate,
272 ArborX::PairValueIndex<Geometry, int>
const& value_pair )
const
274 int const primitive_index = value_pair.index;
275 int const predicate_index = getData( predicate );
276 auto& count = counts( predicate_index );
277 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
279 if ( count < (
int)neighbors.extent( 1 ) )
281 neighbors( predicate_index, count++ ) =
291 template <
typename Predicate>
292 KOKKOS_FUNCTION
void operator()( Predicate
const& predicate,
293 int primitive_index )
const
295 int const predicate_index = getData( predicate );
296 auto& count = counts( predicate_index );
297 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
299 if ( count < (
int)neighbors.extent( 1 ) )
301 neighbors( predicate_index, count++ ) =
314template <
typename Counts,
typename Neighbors,
typename Tag>
315struct NeighborDiscriminatorCallback2D_SecondPass
319#if ARBORX_VERSION >= 10799
320 template <
typename Predicate,
typename Geometry>
322 operator()( Predicate
const& predicate,
323 ArborX::PairValueIndex<Geometry, int>
const& value_pair )
const
325 int const primitive_index = value_pair.index;
326 int const predicate_index = getData( predicate );
327 auto& count = counts( predicate_index );
328 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
330 assert( count < (
int)neighbors.extent( 1 ) );
331 neighbors( predicate_index, count++ ) =
336 template <
typename Predicate>
337 KOKKOS_FUNCTION
void operator()( Predicate
const& predicate,
338 int primitive_index )
const
340 int const predicate_index = getData( predicate );
341 auto& count = counts( predicate_index );
342 if ( CollisionFilter<Tag>::keep( predicate_index, primitive_index ) )
344 assert( count < (
int)neighbors.extent( 1 ) );
345 neighbors( predicate_index, count++ ) =
360template <
typename MemorySpace,
typename Tag>
368 typename MemorySpace::size_type
shift;
370 typename MemorySpace::size_type
total;
394template <
typename ExecutionSpace,
typename Positions,
typename Tag>
396 typename Positions::size_type first,
397 typename Positions::size_type last,
398 typename Positions::value_type radius,
399 int buffer_size = 0 )
401 assert( buffer_size >= 0 );
402 assert( last >= first );
403 assert( last <= positions.size() );
405 using memory_space =
typename Positions::memory_space;
407#if ARBORX_VERSION >= 10799
408 ArborX::BoundingVolumeHierarchy bvh(
409 space, ArborX::Experimental::attach_indices<int>( positions ) );
411 ArborX::BVH<memory_space> bvh( space, positions );
414 Kokkos::View<int*, memory_space> indices(
415 Kokkos::view_alloc(
"indices", Kokkos::WithoutInitializing ), 0 );
416 Kokkos::View<int*, memory_space> offset(
417 Kokkos::view_alloc(
"offset", Kokkos::WithoutInitializing ), 0 );
419 space, Impl::makePredicates( positions, first, last, radius ),
420 Impl::NeighborDiscriminatorCallback<Tag>{}, indices, offset,
421 ArborX::Experimental::TraversalPolicy().setBufferSize( buffer_size ) );
424 std::move( indices ), std::move( offset ), first, bvh.size() };
445template <
typename Positions,
typename Tag>
447 typename Positions::size_type first,
448 typename Positions::size_type last,
449 typename Positions::value_type radius,
450 int buffer_size = 0 )
452 typename Positions::execution_space space{};
476template <
typename DeviceType,
typename Positions,
typename Tag>
478 typename Positions::size_type first,
479 typename Positions::size_type last,
480 typename Positions::value_type radius,
481 int buffer_size = 0 )
483 using exec_space =
typename DeviceType::execution_space;
490template <
typename MemorySpace,
typename Tag>
494 Kokkos::View<int*, MemorySpace>
cnt;
496 Kokkos::View<int**, MemorySpace>
val;
498 typename MemorySpace::size_type
shift;
500 typename MemorySpace::size_type
total;
524template <
typename ExecutionSpace,
typename Positions,
typename Tag>
526 typename Positions::size_type first,
527 typename Positions::size_type last,
528 typename Positions::value_type radius,
529 int buffer_size = 0 )
531 assert( buffer_size >= 0 );
532 assert( last >= first );
533 assert( last <= positions.size() );
535 using memory_space =
typename Positions::memory_space;
537#if ARBORX_VERSION >= 10799
538 ArborX::BoundingVolumeHierarchy bvh(
539 space, ArborX::Experimental::attach_indices<int>( positions ) );
541 ArborX::BVH<memory_space> bvh( space, positions );
544 auto const predicates =
545 Impl::makePredicates( positions, first, last, radius );
547 auto const n_queries =
548 ArborX::AccessTraits<std::remove_const_t<
decltype( predicates )>
549#
if ARBORX_VERSION < 10799
551 ArborX::PredicatesTag
555 Kokkos::View<int**, memory_space> neighbors;
556 Kokkos::View<int*, memory_space> counts(
"counts", n_queries );
557 if ( buffer_size > 0 )
559 neighbors = Kokkos::View<int**, memory_space>(
560 Kokkos::view_alloc(
"neighbors", Kokkos::WithoutInitializing ),
561 n_queries, buffer_size );
564 Impl::NeighborDiscriminatorCallback2D_FirstPass_BufferOptimization<
565 decltype( counts ),
decltype( neighbors ), Tag>{ counts,
572 Impl::NeighborDiscriminatorCallback2D_FirstPass<
decltype( counts ),
576 auto const max_neighbors = Impl::max_reduce( space, counts );
577 if ( max_neighbors <= buffer_size )
586 neighbors = Kokkos::View<int**, memory_space>(
587 Kokkos::view_alloc(
"neighbors", Kokkos::WithoutInitializing ),
588 n_queries, max_neighbors );
589 Kokkos::deep_copy( counts, 0 );
590 bvh.query( space, predicates,
591 Impl::NeighborDiscriminatorCallback2D_SecondPass<
592 decltype( counts ),
decltype( neighbors ), Tag>{
593 counts, neighbors } );
617template <
typename Positions,
typename Tag>
619 typename Positions::size_type first,
620 typename Positions::size_type last,
621 typename Positions::value_type radius,
622 int buffer_size = 0 )
624 using exec_space =
typename Positions::execution_space;
626 radius, buffer_size );
649template <
typename DeviceType,
typename Positions,
typename Tag>
651 typename Positions::size_type first,
652 typename Positions::size_type last,
653 typename Positions::value_type radius,
654 int buffer_size = 0 )
656 using exec_space =
typename DeviceType::execution_space;
658 radius, buffer_size );
664template <
typename MemorySpace,
typename Tag>
668 using size_type = std::size_t;
677 KOKKOS_INLINE_FUNCTION
684 KOKKOS_INLINE_FUNCTION
691 static KOKKOS_FUNCTION size_type
694 assert( (
int)p >= 0 && p < crs_graph.
total );
695 p -= crs_graph.
shift;
696 if ( (
int)p < 0 || p >= crs_graph.
row_ptr.size() - 1 )
701 static KOKKOS_FUNCTION size_type
702 getNeighbor( crs_graph_type
const& crs_graph, size_type p, size_type n )
705 p -= crs_graph.
shift;
711template <
typename MemorySpace,
typename Tag>
715 using size_type = std::size_t;
724 KOKKOS_INLINE_FUNCTION
731 KOKKOS_INLINE_FUNCTION
738 static KOKKOS_FUNCTION size_type
numNeighbor( specialization_type
const& d,
741 assert( (
int)p >= 0 && p < d.
total );
743 if ( (
int)p < 0 || p >= d.
cnt.size() )
748 static KOKKOS_FUNCTION size_type
getNeighbor( specialization_type
const& d,
749 size_type p, size_type n )
753 return d.
val( p, n );
auto makeNeighborList(ExecutionSpace space, Tag, Positions const &positions, typename Positions::size_type first, typename Positions::size_type last, typename Positions::value_type radius, int buffer_size=0)
Neighbor list implementation using ArborX for particles within the interaction distance with a 1D com...
Definition Cabana_Experimental_NeighborList.hpp:395
auto make2DNeighborList(ExecutionSpace space, Tag, Positions const &positions, typename Positions::size_type first, typename Positions::size_type last, typename Positions::value_type radius, int buffer_size=0)
Neighbor list implementation using ArborX for particles within the interaction distance with a 2D lay...
Definition Cabana_Experimental_NeighborList.hpp:525
KOKKOS_INLINE_FUNCTION std::size_t maxNeighbor(const ListType &list, const std::size_t num_particles)
Iterate to find the maximum number of neighbors.
Definition Cabana_NeighborList.hpp:164
KOKKOS_INLINE_FUNCTION std::size_t totalNeighbor(const ListType &list, const std::size_t num_particles)
Iterate to get the total number of neighbors.
Definition Cabana_NeighborList.hpp:152
Slice a single particle property from an AoSoA.
Memory access type checking.
static KOKKOS_INLINE_FUNCTION size_type totalNeighbor(crs_graph_type const &crs_graph)
Get the total number of neighbors across all particles.
Definition Cabana_Experimental_NeighborList.hpp:678
static KOKKOS_FUNCTION size_type getNeighbor(crs_graph_type const &crs_graph, size_type p, size_type n)
Get the id for a neighbor for a given particle index and neighbor index.
Definition Cabana_Experimental_NeighborList.hpp:702
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:674
static KOKKOS_INLINE_FUNCTION size_type maxNeighbor(crs_graph_type const &crs_graph)
Get the maximum number of neighbors across all particles.
Definition Cabana_Experimental_NeighborList.hpp:685
static KOKKOS_FUNCTION size_type numNeighbor(crs_graph_type const &crs_graph, size_type p)
Get the number of neighbors for a given particle index.
Definition Cabana_Experimental_NeighborList.hpp:692
static KOKKOS_INLINE_FUNCTION size_type totalNeighbor(specialization_type const &d)
Get the total number of neighbors across all particles.
Definition Cabana_Experimental_NeighborList.hpp:725
static KOKKOS_FUNCTION size_type numNeighbor(specialization_type const &d, size_type p)
Get the number of neighbors for a given particle index.
Definition Cabana_Experimental_NeighborList.hpp:738
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:721
static KOKKOS_INLINE_FUNCTION size_type maxNeighbor(specialization_type const &d)
Get the maximum number of neighbors across all particles.
Definition Cabana_Experimental_NeighborList.hpp:732
static KOKKOS_FUNCTION size_type getNeighbor(specialization_type const &d, size_type p, size_type n)
Get the id for a neighbor for a given particle index and neighbor index.
Definition Cabana_Experimental_NeighborList.hpp:748
Neighbor list interface. Provides an interface callable at the functor level that gives access to nei...
Definition Cabana_NeighborList.hpp:114
static KOKKOS_INLINE_FUNCTION std::size_t numNeighbor(const NeighborListType &list, const std::size_t particle_index)
Get the number of neighbors for a given particle index.
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
auto size(SliceType slice, typename std::enable_if< is_slice< SliceType >::value, int >::type *=0)
Check slice size (differs from Kokkos View).
Definition Cabana_Slice.hpp:1012
static KOKKOS_FUNCTION auto get(PositionLike const &x, size_type i)
Get the particle at the index.
Definition Cabana_Experimental_NeighborList.hpp:155
static KOKKOS_FUNCTION size_type size(PositionLike const &x)
Get number of particles.
Definition Cabana_Experimental_NeighborList.hpp:150
typename PositionLike::memory_space memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:146
typename PositionLike::size_type size_type
Size type.
Definition Cabana_Experimental_NeighborList.hpp:148
Cabana::Experimental::Impl::SubPositionsAndRadius< Positions > PositionLike
Position wrapper with partial range and radius information.
Definition Cabana_Experimental_NeighborList.hpp:143
static KOKKOS_FUNCTION size_type size(Positions const &x)
Get number of particles.
Definition Cabana_Experimental_NeighborList.hpp:121
typename Positions::size_type size_type
Size type.
Definition Cabana_Experimental_NeighborList.hpp:119
typename Positions::memory_space memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:117
static KOKKOS_FUNCTION auto get(Positions const &x, size_type i)
Get the particle at the index.
Definition Cabana_Experimental_NeighborList.hpp:126
1d ArborX neighbor list storage layout.
Definition Cabana_Experimental_NeighborList.hpp:362
Kokkos::View< int *, MemorySpace > row_ptr
Neighbor offsets.
Definition Cabana_Experimental_NeighborList.hpp:366
MemorySpace::size_type total
Total particles.
Definition Cabana_Experimental_NeighborList.hpp:370
MemorySpace::size_type shift
Neighbor offset shift.
Definition Cabana_Experimental_NeighborList.hpp:368
Kokkos::View< int *, MemorySpace > col_ind
Neighbor indices.
Definition Cabana_Experimental_NeighborList.hpp:364
2d ArborX neighbor list storage layout.
Definition Cabana_Experimental_NeighborList.hpp:492
MemorySpace::size_type total
Total particles.
Definition Cabana_Experimental_NeighborList.hpp:500
Kokkos::View< int *, MemorySpace > cnt
Neighbor counts.
Definition Cabana_Experimental_NeighborList.hpp:494
MemorySpace::size_type shift
Neighbor offset shift.
Definition Cabana_Experimental_NeighborList.hpp:498
Kokkos::View< int **, MemorySpace > val
Neighbor indices.
Definition Cabana_Experimental_NeighborList.hpp:496