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{};
459template <
typename MemorySpace,
typename Tag>
463 Kokkos::View<int*, MemorySpace>
cnt;
465 Kokkos::View<int**, MemorySpace>
val;
467 typename MemorySpace::size_type
shift;
469 typename MemorySpace::size_type
total;
493template <
typename ExecutionSpace,
typename Positions,
typename Tag>
495 typename Positions::size_type first,
496 typename Positions::size_type last,
497 typename Positions::value_type radius,
498 int buffer_size = 0 )
500 assert( buffer_size >= 0 );
501 assert( last >= first );
502 assert( last <= positions.size() );
504 using memory_space =
typename Positions::memory_space;
506#if ARBORX_VERSION >= 10799
507 ArborX::BoundingVolumeHierarchy bvh(
508 space, ArborX::Experimental::attach_indices<int>( positions ) );
510 ArborX::BVH<memory_space> bvh( space, positions );
513 auto const predicates =
514 Impl::makePredicates( positions, first, last, radius );
516 auto const n_queries =
517 ArborX::AccessTraits<std::remove_const_t<
decltype( predicates )>
518#
if ARBORX_VERSION < 10799
520 ArborX::PredicatesTag
524 Kokkos::View<int**, memory_space> neighbors;
525 Kokkos::View<int*, memory_space> counts(
"counts", n_queries );
526 if ( buffer_size > 0 )
528 neighbors = Kokkos::View<int**, memory_space>(
529 Kokkos::view_alloc(
"neighbors", Kokkos::WithoutInitializing ),
530 n_queries, buffer_size );
533 Impl::NeighborDiscriminatorCallback2D_FirstPass_BufferOptimization<
534 decltype( counts ),
decltype( neighbors ), Tag>{ counts,
541 Impl::NeighborDiscriminatorCallback2D_FirstPass<
decltype( counts ),
545 auto const max_neighbors = Impl::max_reduce( space, counts );
546 if ( max_neighbors <= buffer_size )
555 neighbors = Kokkos::View<int**, memory_space>(
556 Kokkos::view_alloc(
"neighbors", Kokkos::WithoutInitializing ),
557 n_queries, max_neighbors );
558 Kokkos::deep_copy( counts, 0 );
559 bvh.query( space, predicates,
560 Impl::NeighborDiscriminatorCallback2D_SecondPass<
561 decltype( counts ),
decltype( neighbors ), Tag>{
562 counts, neighbors } );
586template <
typename Positions,
typename Tag>
588 typename Positions::size_type first,
589 typename Positions::size_type last,
590 typename Positions::value_type radius,
591 int buffer_size = 0 )
593 using exec_space =
typename Positions::execution_space;
595 radius, buffer_size );
601template <
typename MemorySpace,
typename Tag>
605 using size_type = std::size_t;
614 KOKKOS_INLINE_FUNCTION
621 KOKKOS_INLINE_FUNCTION
628 static KOKKOS_FUNCTION size_type
631 assert( (
int)p >= 0 && p < crs_graph.
total );
632 p -= crs_graph.
shift;
633 if ( (
int)p < 0 || p >= crs_graph.
row_ptr.size() - 1 )
638 static KOKKOS_FUNCTION size_type
639 getNeighbor( crs_graph_type
const& crs_graph, size_type p, size_type n )
642 p -= crs_graph.
shift;
648template <
typename MemorySpace,
typename Tag>
652 using size_type = std::size_t;
661 KOKKOS_INLINE_FUNCTION
668 KOKKOS_INLINE_FUNCTION
675 static KOKKOS_FUNCTION size_type
numNeighbor( specialization_type
const& d,
678 assert( (
int)p >= 0 && p < d.
total );
680 if ( (
int)p < 0 || p >= d.
cnt.size() )
685 static KOKKOS_FUNCTION size_type
getNeighbor( specialization_type
const& d,
686 size_type p, size_type n )
690 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:494
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:615
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:639
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:611
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:622
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:629
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:662
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:675
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Experimental_NeighborList.hpp:658
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:669
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:685
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:1019
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:461
MemorySpace::size_type total
Total particles.
Definition Cabana_Experimental_NeighborList.hpp:469
Kokkos::View< int *, MemorySpace > cnt
Neighbor counts.
Definition Cabana_Experimental_NeighborList.hpp:463
MemorySpace::size_type shift
Neighbor offset shift.
Definition Cabana_Experimental_NeighborList.hpp:467
Kokkos::View< int **, MemorySpace > val
Neighbor indices.
Definition Cabana_Experimental_NeighborList.hpp:465