Skip to content

Commit a880e07

Browse files
authored
Merge pull request #812 from streeve/reciprocal_neighbors
Guarantee reciprocal neighbors
2 parents e6bad66 + ed3c8e7 commit a880e07

File tree

2 files changed

+70
-17
lines changed

2 files changed

+70
-17
lines changed

core/src/Cabana_VerletList.hpp

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -235,16 +235,69 @@ struct VerletListBuilder
235235
rsqr = neighborhood_radius * neighborhood_radius;
236236
}
237237

238-
KOKKOS_INLINE_FUNCTION auto cutoff( [[maybe_unused]] const int p ) const
238+
// Check if particle pair i-j is within cutoff, potentially with variable
239+
// radii.
240+
KOKKOS_INLINE_FUNCTION auto withinCutoff( [[maybe_unused]] const int i,
241+
const double dist_sqr ) const
239242
{
240243
// Square the radius on the fly if using a per-particle field to avoid a
241244
// deep copy.
242245
if constexpr ( is_slice<RadiusType>::value ||
243246
Kokkos::is_view<RadiusType>::value )
244-
return radius( p ) * radius( p );
247+
return dist_sqr <= radius( i ) * radius( i );
245248
// This value is already squared.
246249
else
247-
return rsqr;
250+
return dist_sqr <= rsqr;
251+
}
252+
253+
// Check if potential neighbor j is NOT within cutoff, meaning particle i
254+
// should add instead for symmetry.
255+
KOKKOS_INLINE_FUNCTION auto
256+
neighborNotWithinCutoff( [[maybe_unused]] const int j,
257+
[[maybe_unused]] const double dist_sqr ) const
258+
{
259+
// This neighbor needs to be added if they will not find this particle.
260+
if constexpr ( is_slice<RadiusType>::value ||
261+
Kokkos::is_view<RadiusType>::value )
262+
{
263+
return dist_sqr >= radius( j ) * radius( j );
264+
}
265+
else
266+
{
267+
// For a fixed radius, this will never occur.
268+
return false;
269+
}
270+
}
271+
272+
// Count neighbors, with consideration for self particle i and neighbor j.
273+
KOKKOS_INLINE_FUNCTION auto countNeighbor( const int i, const int j,
274+
const double dist_sqr ) const
275+
{
276+
int c = 0;
277+
// Always add self if within cutoff.
278+
if ( withinCutoff( i, dist_sqr ) )
279+
{
280+
c++;
281+
// Add neighbor if they will not find this particle.
282+
if ( neighborNotWithinCutoff( j, dist_sqr ) )
283+
c++;
284+
}
285+
return c;
286+
}
287+
288+
// Add neighbors, with consideration for self particle i and neighbor j.
289+
KOKKOS_INLINE_FUNCTION void addNeighbor( const int i, const int j,
290+
const double dist_sqr ) const
291+
{
292+
// Always add self if within cutoff.
293+
if ( withinCutoff( i, dist_sqr ) )
294+
{
295+
_data.addNeighbor( i, j );
296+
297+
// Add neighbor if they will not find this particle.
298+
if ( neighborNotWithinCutoff( j, dist_sqr ) )
299+
_data.addNeighbor( j, i );
300+
}
248301
}
249302

250303
// Neighbor count team operator (only used for CSR lists).
@@ -295,9 +348,11 @@ struct VerletListBuilder
295348
{
296349
// See if we should actually check this box for
297350
// neighbors.
298-
if ( linked_cell_list.cellStencil()
299-
.grid.minDistanceToPoint(
300-
x_p, y_p, z_p, i, j, k ) <= rsqr )
351+
if ( withinCutoff(
352+
pid,
353+
linked_cell_list.cellStencil()
354+
.grid.minDistanceToPoint(
355+
x_p, y_p, z_p, i, j, k ) ) )
301356
{
302357
std::size_t n_offset =
303358
linked_cell_list.binOffset( i, j, k );
@@ -373,8 +428,7 @@ struct VerletListBuilder
373428
PositionValueType dist_sqr = dx * dx + dy * dy + dz * dz;
374429

375430
// If within the cutoff add to the count.
376-
if ( dist_sqr <= cutoff( pid ) )
377-
local_count += 1;
431+
local_count += countNeighbor( pid, nid, dist_sqr );
378432
}
379433
}
380434

@@ -512,9 +566,11 @@ struct VerletListBuilder
512566
{
513567
// See if we should actually check this box for
514568
// neighbors.
515-
if ( linked_cell_list.cellStencil()
516-
.grid.minDistanceToPoint(
517-
x_p, y_p, z_p, i, j, k ) <= rsqr )
569+
if ( withinCutoff(
570+
pid,
571+
linked_cell_list.cellStencil()
572+
.grid.minDistanceToPoint(
573+
x_p, y_p, z_p, i, j, k ) ) )
518574
{
519575
// Check the particles in this bin to see if
520576
// they are neighbors.
@@ -583,10 +639,7 @@ struct VerletListBuilder
583639

584640
// If within the cutoff increment the neighbor count and add as a
585641
// neighbor at that index.
586-
if ( dist_sqr <= cutoff( pid ) )
587-
{
588-
_data.addNeighbor( pid, nid );
589-
}
642+
addNeighbor( pid, nid, dist_sqr );
590643
}
591644
}
592645
};

core/unit_test/tstNeighborList.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ void testNonUniformRadius()
214214
// Create the AoSoA and fill custom particle details.
215215
std::size_t particle_x = 2;
216216
// Purposely choose radius to reach all particles.
217-
double large_radius = 4.35;
217+
double large_radius = 4.05;
218218
// Purposely choose radius to reach nearest neighbors only.
219219
double small_radius = 3.32;
220220
// Create the AoSoA and fill with particles
@@ -249,7 +249,7 @@ void testNonUniformRadius()
249249
if ( p == 0 || p == test_data.num_particle - 1 )
250250
EXPECT_EQ( list_copy.counts( p ), 6 );
251251
else
252-
EXPECT_EQ( list_copy.counts( p ), 3 );
252+
EXPECT_EQ( list_copy.counts( p ), 4 );
253253
}
254254
}
255255

0 commit comments

Comments
 (0)