@@ -123,13 +123,13 @@ namespace Impl
123123// ---------------------------------------------------------------------------//
124124// Verlet List Builder
125125// ---------------------------------------------------------------------------//
126- template <class DeviceType , class PositionType , class RandomAccessPositionType ,
126+ template <class DeviceType , class RandomAccessPositionType , class RadiusType ,
127127 class AlgorithmTag , class LayoutTag , class BuildOpTag >
128128struct VerletListBuilder
129129{
130130 // Types.
131131 using device = DeviceType;
132- using PositionValueType = typename PositionType ::value_type;
132+ using PositionValueType = typename RandomAccessPositionType ::value_type;
133133 using memory_space = typename device::memory_space;
134134 using execution_space = typename device::execution_space;
135135
@@ -138,6 +138,8 @@ struct VerletListBuilder
138138
139139 // Neighbor cutoff.
140140 PositionValueType rsqr;
141+ // Per-particle cutoff, if used.
142+ RadiusType rsqr_p;
141143
142144 // Positions.
143145 RandomAccessPositionType _position;
@@ -155,16 +157,56 @@ struct VerletListBuilder
155157 std::size_t alloc_n;
156158
157159 // Constructor.
160+ template <class PositionType >
161+ VerletListBuilder ( PositionType positions, const std::size_t begin,
162+ const std::size_t end,
163+ const PositionValueType neighborhood_radius,
164+ const PositionValueType cell_size_ratio,
165+ const PositionValueType grid_min[3 ],
166+ const PositionValueType grid_max[3 ],
167+ const std::size_t max_neigh )
168+ : pid_begin( begin )
169+ , pid_end( end )
170+ , alloc_n( max_neigh )
171+ {
172+ init ( positions, neighborhood_radius, cell_size_ratio, grid_min,
173+ grid_max );
174+ }
175+
176+ // Constructor.
177+ template <class PositionType >
158178 VerletListBuilder ( PositionType positions, const std::size_t begin,
159179 const std::size_t end,
160180 const PositionValueType neighborhood_radius,
181+ const RadiusType radius,
161182 const PositionValueType cell_size_ratio,
162183 const PositionValueType grid_min[3 ],
163184 const PositionValueType grid_max[3 ],
164185 const std::size_t max_neigh )
165186 : pid_begin( begin )
166187 , pid_end( end )
167188 , alloc_n( max_neigh )
189+ {
190+ assert ( positions.size () == radius.size () );
191+ init ( positions, neighborhood_radius, cell_size_ratio, grid_min,
192+ grid_max );
193+
194+ // We will use the square of the distance, per particle, for neighbor
195+ // determination.
196+ Kokkos::RangePolicy<execution_space> policy ( begin, end );
197+ Kokkos::parallel_for (
198+ policy, KOKKOS_LAMBDA ( const int p ) {
199+ radius ( p ) = radius ( p ) * radius ( p );
200+ } );
201+ rsqr_p = radius;
202+ }
203+
204+ template <class PositionType >
205+ void init ( PositionType positions,
206+ const PositionValueType neighborhood_radius,
207+ const PositionValueType cell_size_ratio,
208+ const PositionValueType grid_min[3 ],
209+ const PositionValueType grid_max[3 ] )
168210 {
169211 count = true ;
170212 refill = false ;
@@ -194,6 +236,15 @@ struct VerletListBuilder
194236 rsqr = neighborhood_radius * neighborhood_radius;
195237 }
196238
239+ KOKKOS_INLINE_FUNCTION auto cutoff ( const int p ) const
240+ {
241+ if constexpr ( is_slice<RadiusType>::value ||
242+ Kokkos::is_view<RadiusType>::value )
243+ return rsqr_p ( p );
244+ else
245+ return rsqr;
246+ }
247+
197248 // Neighbor count team operator (only used for CSR lists).
198249 struct CountNeighborsTag
199250 {
@@ -320,7 +371,7 @@ struct VerletListBuilder
320371 PositionValueType dist_sqr = dx * dx + dy * dy + dz * dz;
321372
322373 // If within the cutoff add to the count.
323- if ( dist_sqr <= rsqr )
374+ if ( dist_sqr <= cutoff ( pid ) )
324375 local_count += 1 ;
325376 }
326377 }
@@ -530,7 +581,7 @@ struct VerletListBuilder
530581
531582 // If within the cutoff increment the neighbor count and add as a
532583 // neighbor at that index.
533- if ( dist_sqr <= rsqr )
584+ if ( dist_sqr <= cutoff ( pid ) )
534585 {
535586 _data.addNeighbor ( pid, nid );
536587 }
@@ -540,8 +591,8 @@ struct VerletListBuilder
540591
541592// Builder creation functions. This is only necessary to define the different
542593// random access types.
543- template <class DeviceType , class PositionType , class AlgorithmTag ,
544- class LayoutTag , class BuildOpTag >
594+ template <class DeviceType , class AlgorithmTag , class LayoutTag ,
595+ class BuildOpTag , class PositionType >
545596auto createVerletListBuilder (
546597 PositionType x, const std::size_t begin, const std::size_t end,
547598 const typename PositionType::value_type radius,
@@ -552,13 +603,14 @@ auto createVerletListBuilder(
552603 typename std::enable_if<( is_slice<PositionType>::value ), int>::type* = 0 )
553604{
554605 using RandomAccessPositionType = typename PositionType::random_access_slice;
555- return VerletListBuilder<DeviceType, PositionType, RandomAccessPositionType,
556- AlgorithmTag, LayoutTag, BuildOpTag>(
606+ return VerletListBuilder<DeviceType, RandomAccessPositionType,
607+ typename PositionType::value_type, AlgorithmTag,
608+ LayoutTag, BuildOpTag>(
557609 x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh );
558610}
559611
560- template <class DeviceType , class PositionType , class AlgorithmTag ,
561- class LayoutTag , class BuildOpTag >
612+ template <class DeviceType , class AlgorithmTag , class LayoutTag ,
613+ class BuildOpTag , class PositionType >
562614auto createVerletListBuilder (
563615 PositionType x, const std::size_t begin, const std::size_t end,
564616 const typename PositionType::value_type radius,
@@ -572,11 +624,53 @@ auto createVerletListBuilder(
572624 using RandomAccessPositionType =
573625 Kokkos::View<typename PositionType::value_type**, DeviceType,
574626 Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
575- return VerletListBuilder<DeviceType, PositionType, RandomAccessPositionType,
576- AlgorithmTag, LayoutTag, BuildOpTag>(
627+ return VerletListBuilder<DeviceType, RandomAccessPositionType,
628+ typename PositionType::value_type, AlgorithmTag,
629+ LayoutTag, BuildOpTag>(
577630 x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh );
578631}
579632
633+ template <class DeviceType , class AlgorithmTag , class LayoutTag ,
634+ class BuildOpTag , class PositionType , class RadiusType >
635+ auto createVerletListBuilder (
636+ PositionType x, const std::size_t begin, const std::size_t end,
637+ const typename PositionType::value_type background_radius,
638+ const RadiusType radius,
639+ const typename PositionType::value_type cell_size_ratio,
640+ const typename PositionType::value_type grid_min[3 ],
641+ const typename PositionType::value_type grid_max[3 ],
642+ const std::size_t max_neigh,
643+ typename std::enable_if<( is_slice<PositionType>::value ), int>::type* = 0 )
644+ {
645+ using RandomAccessPositionType = typename PositionType::random_access_slice;
646+ return VerletListBuilder<DeviceType, RandomAccessPositionType, RadiusType,
647+ AlgorithmTag, LayoutTag, BuildOpTag>(
648+ x, begin, end, background_radius, radius, cell_size_ratio, grid_min,
649+ grid_max, max_neigh );
650+ }
651+
652+ template <class DeviceType , class AlgorithmTag , class LayoutTag ,
653+ class BuildOpTag , class PositionType , class RadiusType >
654+ auto createVerletListBuilder (
655+ PositionType x, const std::size_t begin, const std::size_t end,
656+ const typename PositionType::value_type background_radius,
657+ const RadiusType radius,
658+ const typename PositionType::value_type cell_size_ratio,
659+ const typename PositionType::value_type grid_min[3 ],
660+ const typename PositionType::value_type grid_max[3 ],
661+ const std::size_t max_neigh,
662+ typename std::enable_if<( Kokkos::is_view<PositionType>::value ),
663+ int>::type* = 0 )
664+ {
665+ using RandomAccessPositionType =
666+ Kokkos::View<typename PositionType::value_type**, DeviceType,
667+ Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
668+ return VerletListBuilder<DeviceType, RandomAccessPositionType, RadiusType,
669+ AlgorithmTag, LayoutTag, BuildOpTag>(
670+ x, begin, end, background_radius, radius, cell_size_ratio, grid_min,
671+ grid_max, max_neigh );
672+ }
673+
580674// ---------------------------------------------------------------------------//
581675
582676// ! \endcond
@@ -671,6 +765,57 @@ class VerletList
671765 grid_max, max_neigh );
672766 }
673767
768+ /* !
769+ \brief VerletList constructor. Given a list of particle positions and
770+ a neighborhood radius calculate the neighbor list.
771+
772+ \param x The slice containing the particle positions
773+
774+ \param begin The beginning particle index to compute neighbors for.
775+
776+ \param end The end particle index to compute neighbors for.
777+
778+ \param background_radius The radius of the neighborhood used
779+ for the background grid cells in each dimension.
780+
781+ \param neighborhood_radius The radius of the neighborhood per particle.
782+ Particles within this radius are considered neighbors.
783+
784+ \param cell_size_ratio The ratio of the cell size in the Cartesian grid
785+ to the neighborhood radius. For example, if the cell size ratio is 0.5
786+ then the cells will be half the size of the neighborhood radius in each
787+ dimension.
788+
789+ \param grid_min The minimum value of the grid containing the particles
790+ in each dimension.
791+
792+ \param grid_max The maximum value of the grid containing the particles
793+ in each dimension.
794+
795+ \param max_neigh Optional maximum number of neighbors per particle to
796+ pre-allocate the neighbor list. Potentially avoids recounting with 2D
797+ layout only.
798+
799+ Particles outside of the neighborhood radius will not be considered
800+ neighbors. Only compute the neighbors of those that are within the given
801+ range. All particles are candidates for being a neighbor, regardless of
802+ whether or not they are in the range.
803+ */
804+ template <class PositionSlice , class RadiusSlice >
805+ VerletList ( PositionSlice x, const std::size_t begin, const std::size_t end,
806+ const typename PositionSlice::value_type background_radius,
807+ RadiusSlice neighborhood_radius,
808+ const typename PositionSlice::value_type cell_size_ratio,
809+ const typename PositionSlice::value_type grid_min[3 ],
810+ const typename PositionSlice::value_type grid_max[3 ],
811+ const std::size_t max_neigh = 0 ,
812+ typename std::enable_if<( is_slice<PositionSlice>::value ),
813+ int >::type* = 0 )
814+ {
815+ build ( x, begin, end, background_radius, neighborhood_radius,
816+ cell_size_ratio, grid_min, grid_max, max_neigh );
817+ }
818+
674819 /* !
675820 \brief Given a list of particle positions and a neighborhood radius
676821 calculate the neighbor list.
@@ -716,26 +861,79 @@ class VerletList
716861 assert ( end <= size ( x ) );
717862
718863 using device_type = Kokkos::Device<ExecutionSpace, memory_space>;
864+ // Create a builder functor.
865+ auto builder = Impl::createVerletListBuilder<device_type, AlgorithmTag,
866+ LayoutTag, BuildTag>(
867+ x, begin, end, neighborhood_radius, cell_size_ratio, grid_min,
868+ grid_max, max_neigh );
869+ buildImpl ( builder );
870+ }
871+
872+ /* !
873+ \brief Given a list of particle positions and a neighborhood radius
874+ calculate the neighbor list.
875+ */
876+ template <class PositionSlice , class RadiusSlice >
877+ void build ( PositionSlice x, const std::size_t begin, const std::size_t end,
878+ const typename PositionSlice::value_type background_radius,
879+ RadiusSlice neighborhood_radius,
880+ const typename PositionSlice::value_type cell_size_ratio,
881+ const typename PositionSlice::value_type grid_min[3 ],
882+ const typename PositionSlice::value_type grid_max[3 ],
883+ const std::size_t max_neigh = 0 )
884+ {
885+ // Use the default execution space.
886+ build ( execution_space{}, x, begin, end, background_radius,
887+ neighborhood_radius, cell_size_ratio, grid_min, grid_max,
888+ max_neigh );
889+ }
890+ /* !
891+ \brief Given a list of particle positions and a neighborhood radius
892+ calculate the neighbor list.
893+ */
894+ template <class PositionSlice , class RadiusSlice , class ExecutionSpace >
895+ void build ( ExecutionSpace, PositionSlice x, const std::size_t begin,
896+ const std::size_t end,
897+ const typename PositionSlice::value_type background_radius,
898+ RadiusSlice neighborhood_radius,
899+ const typename PositionSlice::value_type cell_size_ratio,
900+ const typename PositionSlice::value_type grid_min[3 ],
901+ const typename PositionSlice::value_type grid_max[3 ],
902+ const std::size_t max_neigh = 0 )
903+ {
904+ Kokkos::Profiling::ScopedRegion region ( " Cabana::VerletList::build" );
905+
906+ static_assert ( is_accessible_from<memory_space, ExecutionSpace>{}, " " );
907+
908+ assert ( end >= begin );
909+ assert ( end <= x.size () );
719910
720911 // Create a builder functor.
721- auto builder =
722- Impl::createVerletListBuilder<device_type, PositionType,
723- AlgorithmTag, LayoutTag, BuildTag>(
724- x, begin, end, neighborhood_radius, cell_size_ratio, grid_min,
725- grid_max, max_neigh );
912+ using device_type = Kokkos::Device<ExecutionSpace, memory_space>;
913+ auto builder = Impl::createVerletListBuilder<device_type, AlgorithmTag,
914+ LayoutTag, BuildTag>(
915+ x, begin, end, background_radius, neighborhood_radius,
916+ cell_size_ratio, grid_min, grid_max, max_neigh );
917+ buildImpl ( builder );
918+ }
726919
920+ // ! \cond Impl
921+ template <class BuilderType >
922+ void buildImpl ( BuilderType builder )
923+ {
727924 // For each particle in the range check each neighboring bin for
728- // neighbor particles. Bins are at least the size of the neighborhood
729- // radius so the bin in which the particle resides and any surrounding
730- // bins are guaranteed to contain the neighboring particles.
731- // For CSR lists, we count, then fill neighbors. For 2D lists, we
732- // count and fill at the same time, unless the array size is exceeded,
733- // at which point only counting is continued to reallocate and refill.
734- typename decltype ( builder )::FillNeighborsPolicy fill_policy (
925+ // neighbor particles. Bins are at least the size of the
926+ // neighborhood radius so the bin in which the particle resides and
927+ // any surrounding bins are guaranteed to contain the neighboring
928+ // particles. For CSR lists, we count, then fill neighbors. For 2D
929+ // lists, we count and fill at the same time, unless the array size
930+ // is exceeded, at which point only counting is continued to
931+ // reallocate and refill.
932+ typename BuilderType::FillNeighborsPolicy fill_policy (
735933 builder.bin_data_1d .numBin (), Kokkos::AUTO, 4 );
736934 if ( builder.count )
737935 {
738- typename decltype ( builder ) ::CountNeighborsPolicy count_policy (
936+ typename BuilderType ::CountNeighborsPolicy count_policy (
739937 builder.bin_data_1d .numBin (), Kokkos::AUTO, 4 );
740938 Kokkos::parallel_for ( " Cabana::VerletList::count_neighbors" ,
741939 count_policy, builder );
@@ -764,6 +962,7 @@ class VerletList
764962 // Get the data from the builder.
765963 _data = builder._data ;
766964 }
965+ // ! \endcond
767966
768967 // ! Modify a neighbor in the list; for example, mark it as a broken bond.
769968 KOKKOS_INLINE_FUNCTION
0 commit comments