Skip to content

Commit 021985e

Browse files
committed
Add per-particle cutoff radius support for VerletList
1 parent b7fbc36 commit 021985e

File tree

3 files changed

+284
-28
lines changed

3 files changed

+284
-28
lines changed

core/src/Cabana_VerletList.hpp

Lines changed: 224 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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>
128128
struct 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>
545596
auto 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>
562614
auto 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

core/unit_test/neighbor_unit_test.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ struct NeighborListTestData
10391039
struct NeighborListTestDataOrdered
10401040
{
10411041
std::size_t num_particle;
1042-
std::size_t num_ignore = 100;
1042+
std::size_t num_ignore;
10431043
double test_radius;
10441044
double box_min = 0.0;
10451045
double box_max = 5.0;
@@ -1048,16 +1048,18 @@ struct NeighborListTestDataOrdered
10481048
double grid_min[3] = { box_min, box_min, box_min };
10491049
double grid_max[3] = { box_max, box_max, box_max };
10501050

1051-
using DataTypes = Cabana::MemberTypes<double[3]>;
1051+
using DataTypes = Cabana::MemberTypes<double[3], double>;
10521052
using AoSoA_t = Cabana::AoSoA<DataTypes, TEST_MEMSPACE>;
10531053
AoSoA_t aosoa;
10541054

10551055
TestNeighborList<typename TEST_EXECSPACE::array_layout, Kokkos::HostSpace>
10561056
N2_list_copy;
10571057

10581058
NeighborListTestDataOrdered( const std::size_t particle_x,
1059+
const std::size_t ignore = 100,
10591060
const std::size_t m = 3 )
10601061
{
1062+
num_ignore = ignore;
10611063
num_particle = particle_x * particle_x * particle_x;
10621064
double dx = ( grid_max[0] - grid_min[0] ) / particle_x;
10631065
// Use a fixed ratio of cutoff / spacing (and include a floating point

0 commit comments

Comments
 (0)