Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_VerletList.hpp
Go to the documentation of this file.
1/****************************************************************************
2 * Copyright (c) 2018-2023 by the Cabana authors *
3 * All rights reserved. *
4 * *
5 * This file is part of the Cabana library. Cabana is distributed under a *
6 * BSD 3-clause license. For the licensing terms see the LICENSE file in *
7 * the top-level directory. *
8 * *
9 * SPDX-License-Identifier: BSD-3-Clause *
10 ****************************************************************************/
11
16#ifndef CABANA_VERLETLIST_HPP
17#define CABANA_VERLETLIST_HPP
18
21#include <Cabana_Parallel.hpp>
22
23#include <Kokkos_Core.hpp>
24#include <Kokkos_Profiling_ScopedRegion.hpp>
25
26#include <cassert>
27
28namespace Cabana
29{
30//---------------------------------------------------------------------------//
31// Verlet List Memory Layout Tag.
32//---------------------------------------------------------------------------//
35{
36};
37
40{
41};
42
43//---------------------------------------------------------------------------//
44// Verlet List Data.
45//---------------------------------------------------------------------------//
46template <class MemorySpace, class LayoutTag>
48
50template <class MemorySpace>
51struct VerletListData<MemorySpace, VerletLayoutCSR>
52{
54 using memory_space = MemorySpace;
55
57 Kokkos::View<int*, memory_space> counts;
58
60 Kokkos::View<int*, memory_space> offsets;
61
63 Kokkos::View<int*, memory_space> neighbors;
64
66 KOKKOS_INLINE_FUNCTION
67 void addNeighbor( const int pid, const int nid ) const
68 {
69 neighbors( offsets( pid ) +
70 Kokkos::atomic_fetch_add( &counts( pid ), 1 ) ) = nid;
71 }
72
74 KOKKOS_INLINE_FUNCTION
75 void setNeighbor( const int pid, const int nid, const int new_id ) const
76 {
77 neighbors( offsets( pid ) + nid ) = new_id;
78 }
79};
80
82template <class MemorySpace>
83struct VerletListData<MemorySpace, VerletLayout2D>
84{
86 using memory_space = MemorySpace;
87
89 Kokkos::View<int*, memory_space> counts;
90
92 Kokkos::View<int**, memory_space> neighbors;
93
96 std::size_t max_n;
97
99 KOKKOS_INLINE_FUNCTION
100 void addNeighbor( const int pid, const int nid ) const
101 {
102 std::size_t count = Kokkos::atomic_fetch_add( &counts( pid ), 1 );
103 if ( count < neighbors.extent( 1 ) )
104 neighbors( pid, count ) = nid;
105 }
106
108 KOKKOS_INLINE_FUNCTION
109 void setNeighbor( const int pid, const int nid, const int new_id ) const
110 {
111 neighbors( pid, nid ) = new_id;
112 }
113};
114
115//---------------------------------------------------------------------------//
116
117//---------------------------------------------------------------------------//
118
119namespace Impl
120{
122
123//---------------------------------------------------------------------------//
124// Verlet List Builder
125//---------------------------------------------------------------------------//
126template <class DeviceType, class RandomAccessPositionType, class RadiusType,
127 class AlgorithmTag, class LayoutTag, class BuildOpTag>
128struct VerletListBuilder
129{
130 // Types.
131 using device = DeviceType;
132 using PositionValueType = typename RandomAccessPositionType::value_type;
133 using memory_space = typename device::memory_space;
134 using execution_space = typename device::execution_space;
135
136 // List data.
137 VerletListData<memory_space, LayoutTag> _data;
138 // Background squared neighbor cutoff.
139 PositionValueType rsqr;
140 // Fixed or per-particle neighbor radius.
141 RadiusType radius;
142
143 // Positions.
144 RandomAccessPositionType _position;
145 std::size_t pid_begin, pid_end;
146
147 // Binning Data.
148 BinningData<memory_space> bin_data_1d;
149 LinkedCellList<memory_space, PositionValueType> linked_cell_list;
150
151 // Check to count or refill.
152 bool refill;
153 bool count;
154
155 // Maximum allocated neighbors per particle
156 std::size_t alloc_n;
157
158 // Constructor with a single cutoff radius.
159 template <class PositionType>
160 VerletListBuilder( PositionType positions, const std::size_t begin,
161 const std::size_t end,
162 const RadiusType neighborhood_radius,
163 const PositionValueType cell_size_ratio,
164 const PositionValueType grid_min[3],
165 const PositionValueType grid_max[3],
166 const std::size_t max_neigh )
167 : pid_begin( begin )
168 , pid_end( end )
169 , alloc_n( max_neigh )
170 {
171 init( positions, neighborhood_radius, cell_size_ratio, grid_min,
172 grid_max );
173 // This value is not currently used, but set to be consistent with the
174 // variable cutoff case below.
175 radius = neighborhood_radius;
176 }
177
178 // Constructor with a background radius (used for the LinkedCellList) and a
179 // per-particle radius.
180 template <class PositionType>
181 VerletListBuilder( PositionType positions, const std::size_t begin,
182 const std::size_t end,
183 const PositionValueType background_radius,
184 const RadiusType neighborhood_radius,
185 const PositionValueType cell_size_ratio,
186 const PositionValueType grid_min[3],
187 const PositionValueType grid_max[3],
188 const std::size_t max_neigh )
189 : pid_begin( begin )
190 , pid_end( end )
191 , alloc_n( max_neigh )
192 {
193 assert( positions.size() == neighborhood_radius.size() );
194 init( positions, background_radius, cell_size_ratio, grid_min,
195 grid_max );
196
197 // Store a shallow copy (not squared).
198 // TODO: for cases where the radii never change, this could be better
199 // optimized with a deep copy of the squared radius instead.
200 radius = neighborhood_radius;
201 }
202
203 template <class PositionType>
204 void init( PositionType positions,
205 const PositionValueType neighborhood_radius,
206 const PositionValueType cell_size_ratio,
207 const PositionValueType grid_min[3],
208 const PositionValueType grid_max[3] )
209 {
210 count = true;
211 refill = false;
212
213 // Create the count view.
214 _data.counts = Kokkos::View<int*, memory_space>( "num_neighbors",
215 size( positions ) );
216
217 // Make a guess for the number of neighbors per particle for 2D lists.
218 initCounts( LayoutTag() );
219
220 // Shallow copy for random access read-only memory.
221 _position = positions;
222
223 // Bin the particles in the grid. Don't actually sort them but make a
224 // permutation vector. Note that we are binning all particles here and
225 // not just the requested range. This is because all particles are
226 // treated as candidates for neighbors.
227 double grid_size = cell_size_ratio * neighborhood_radius;
228 PositionValueType grid_delta[3] = { grid_size, grid_size, grid_size };
229 linked_cell_list = createLinkedCellList<memory_space>(
230 _position, grid_delta, grid_min, grid_max, neighborhood_radius,
231 cell_size_ratio );
232 bin_data_1d = linked_cell_list.binningData();
233
234 // We will use the square of the distance for neighbor determination.
235 rsqr = neighborhood_radius * neighborhood_radius;
236 }
237
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
242 {
243 // Square the radius on the fly if using a per-particle field to avoid a
244 // deep copy.
245 if constexpr ( is_slice<RadiusType>::value ||
246 Kokkos::is_view<RadiusType>::value )
247 return dist_sqr <= radius( i ) * radius( i );
248 // This value is already squared.
249 else
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 }
301 }
302
303 // Neighbor count team operator (only used for CSR lists).
304 struct CountNeighborsTag
305 {
306 };
307 using CountNeighborsPolicy =
308 Kokkos::TeamPolicy<execution_space, CountNeighborsTag,
309 Kokkos::IndexType<int>,
310 Kokkos::Schedule<Kokkos::Dynamic>>;
311
312 KOKKOS_INLINE_FUNCTION
313 void
314 operator()( const CountNeighborsTag&,
315 const typename CountNeighborsPolicy::member_type& team ) const
316 {
317 // The league rank of the team is the cardinal cell index we are
318 // working on.
319 int cell = team.league_rank();
320
321 // Get the stencil for this cell.
322 int imin, imax, jmin, jmax, kmin, kmax;
323 linked_cell_list.getStencilCells( cell, imin, imax, jmin, jmax, kmin,
324 kmax );
325
326 // Operate on the particles in the bin.
327 std::size_t b_offset = bin_data_1d.binOffset( cell );
328 Kokkos::parallel_for(
329 Kokkos::TeamThreadRange( team, 0, bin_data_1d.binSize( cell ) ),
330 [&]( const int bi )
331 {
332 // Get the true particle id. The binned particle index is the
333 // league rank of the team.
334 std::size_t pid = linked_cell_list.permutation( bi + b_offset );
335
336 if ( ( pid >= pid_begin ) && ( pid < pid_end ) )
337 {
338 // Cache the particle coordinates.
339 double x_p = _position( pid, 0 );
340 double y_p = _position( pid, 1 );
341 double z_p = _position( pid, 2 );
342
343 // Loop over the cell stencil.
344 int stencil_count = 0;
345 for ( int i = imin; i < imax; ++i )
346 for ( int j = jmin; j < jmax; ++j )
347 for ( int k = kmin; k < kmax; ++k )
348 {
349 // See if we should actually check this box for
350 // neighbors.
351 if ( withinCutoff(
352 pid,
353 linked_cell_list.cellStencil()
354 .grid.minDistanceToPoint(
355 x_p, y_p, z_p, i, j, k ) ) )
356 {
357 std::size_t n_offset =
358 linked_cell_list.binOffset( i, j, k );
359 std::size_t num_n =
360 linked_cell_list.binSize( i, j, k );
361
362 // Check the particles in this bin to see if
363 // they are neighbors. If they are add to
364 // the count for this bin.
365 int cell_count = 0;
366 neighbor_reduce( team, pid, x_p, y_p, z_p,
367 n_offset, num_n,
368 cell_count, BuildOpTag() );
369 stencil_count += cell_count;
370 }
371 }
372 Kokkos::single( Kokkos::PerThread( team ), [&]()
373 { _data.counts( pid ) = stencil_count; } );
374 }
375 } );
376 }
377
378 // Neighbor count team vector loop (only used for CSR lists).
379 KOKKOS_INLINE_FUNCTION void
380 neighbor_reduce( const typename CountNeighborsPolicy::member_type& team,
381 const std::size_t pid, const double x_p, const double y_p,
382 const double z_p, const int n_offset, const int num_n,
383 int& cell_count, TeamVectorOpTag ) const
384 {
385 Kokkos::parallel_reduce(
386 Kokkos::ThreadVectorRange( team, num_n ),
387 [&]( const int n, int& local_count ) {
388 neighbor_kernel( pid, x_p, y_p, z_p, n_offset, n, local_count );
389 },
390 cell_count );
391 }
392
393 // Neighbor count serial loop (only used for CSR lists).
394 KOKKOS_INLINE_FUNCTION
395 void neighbor_reduce( const typename CountNeighborsPolicy::member_type,
396 const std::size_t pid, const double x_p,
397 const double y_p, const double z_p,
398 const int n_offset, const int num_n, int& cell_count,
399 TeamOpTag ) const
400 {
401 for ( int n = 0; n < num_n; n++ )
402 neighbor_kernel( pid, x_p, y_p, z_p, n_offset, n, cell_count );
403 }
404
405 // Neighbor count kernel
406 KOKKOS_INLINE_FUNCTION
407 void neighbor_kernel( const int pid, const double x_p, const double y_p,
408 const double z_p, const int n_offset, const int n,
409 int& local_count ) const
410 {
411 // Get the true id of the candidate neighbor.
412 std::size_t nid = linked_cell_list.permutation( n_offset + n );
413
414 // Cache the candidate neighbor particle coordinates.
415 double x_n = _position( nid, 0 );
416 double y_n = _position( nid, 1 );
417 double z_n = _position( nid, 2 );
418
419 // If this could be a valid neighbor, continue.
420 if ( NeighborDiscriminator<AlgorithmTag>::isValid(
421 pid, x_p, y_p, z_p, nid, x_n, y_n, z_n ) )
422 {
423 // Calculate the distance between the particle and its candidate
424 // neighbor.
425 PositionValueType dx = x_p - x_n;
426 PositionValueType dy = y_p - y_n;
427 PositionValueType dz = z_p - z_n;
428 PositionValueType dist_sqr = dx * dx + dy * dy + dz * dz;
429
430 // If within the cutoff add to the count.
431 local_count += countNeighbor( pid, nid, dist_sqr );
432 }
433 }
434
435 // Process the CSR counts by computing offsets and allocating the neighbor
436 // list.
437 template <class KokkosMemorySpace>
438 struct OffsetScanOp
439 {
440 using kokkos_mem_space = KokkosMemorySpace;
441 Kokkos::View<int*, kokkos_mem_space> counts;
442 Kokkos::View<int*, kokkos_mem_space> offsets;
443 KOKKOS_INLINE_FUNCTION
444 void operator()( const int i, int& update, const bool final_pass ) const
445 {
446 if ( final_pass )
447 offsets( i ) = update;
448 update += counts( i );
449 }
450 };
451
452 void initCounts( VerletLayoutCSR ) {}
453
454 void initCounts( VerletLayout2D )
455 {
456 if ( alloc_n > 0 )
457 {
458 count = false;
459
460 _data.neighbors = Kokkos::View<int**, memory_space>(
461 Kokkos::ViewAllocateWithoutInitializing( "neighbors" ),
462 _data.counts.size(), alloc_n );
463 }
464 }
465
466 void processCounts( VerletLayoutCSR )
467 {
468 // Allocate offsets.
469 _data.offsets = Kokkos::View<int*, memory_space>(
470 Kokkos::ViewAllocateWithoutInitializing( "neighbor_offsets" ),
471 _data.counts.size() );
472
473 // Calculate offsets from counts and the total number of counts.
474 OffsetScanOp<memory_space> offset_op;
475 offset_op.counts = _data.counts;
476 offset_op.offsets = _data.offsets;
477 int total_num_neighbor;
478 Kokkos::RangePolicy<execution_space> range_policy(
479 0, _data.counts.extent( 0 ) );
480 Kokkos::parallel_scan( "Cabana::VerletListBuilder::offset_scan",
481 range_policy, offset_op, total_num_neighbor );
482 Kokkos::fence();
483
484 // Allocate the neighbor list.
485 _data.neighbors = Kokkos::View<int*, memory_space>(
486 Kokkos::ViewAllocateWithoutInitializing( "neighbors" ),
487 total_num_neighbor );
488
489 // Reset the counts. We count again when we fill.
490 Kokkos::deep_copy( _data.counts, 0 );
491 }
492
493 // Process 2D counts by computing the maximum number of neighbors and
494 // reallocating the 2D data structure if needed.
495 void processCounts( VerletLayout2D )
496 {
497 // Calculate the maximum number of neighbors.
498 auto counts = _data.counts;
499 int max;
500 Kokkos::Max<int> max_reduce( max );
501 Kokkos::parallel_reduce(
502 "Cabana::VerletListBuilder::reduce_max",
503 Kokkos::RangePolicy<execution_space>( 0, _data.counts.size() ),
504 KOKKOS_LAMBDA( const int i, int& value ) {
505 if ( counts( i ) > value )
506 value = counts( i );
507 },
508 max_reduce );
509 Kokkos::fence();
510 _data.max_n = static_cast<std::size_t>( max );
511
512 // Reallocate the neighbor list if previous size is exceeded.
513 if ( count or _data.max_n > _data.neighbors.extent( 1 ) )
514 {
515 refill = true;
516 Kokkos::deep_copy( _data.counts, 0 );
517 _data.neighbors = Kokkos::View<int**, memory_space>(
518 Kokkos::ViewAllocateWithoutInitializing( "neighbors" ),
519 _data.counts.size(), _data.max_n );
520 }
521 }
522
523 // Neighbor count team operator.
524 struct FillNeighborsTag
525 {
526 };
527 using FillNeighborsPolicy =
528 Kokkos::TeamPolicy<execution_space, FillNeighborsTag,
529 Kokkos::IndexType<int>,
530 Kokkos::Schedule<Kokkos::Dynamic>>;
531 KOKKOS_INLINE_FUNCTION
532 void
533 operator()( const FillNeighborsTag&,
534 const typename FillNeighborsPolicy::member_type& team ) const
535 {
536 // The league rank of the team is the cardinal cell index we are
537 // working on.
538 int cell = team.league_rank();
539
540 // Get the stencil for this cell.
541 int imin, imax, jmin, jmax, kmin, kmax;
542 linked_cell_list.getStencilCells( cell, imin, imax, jmin, jmax, kmin,
543 kmax );
544
545 // Operate on the particles in the bin.
546 std::size_t b_offset = bin_data_1d.binOffset( cell );
547 Kokkos::parallel_for(
548 Kokkos::TeamThreadRange( team, 0, bin_data_1d.binSize( cell ) ),
549 [&]( const int bi )
550 {
551 // Get the true particle id. The binned particle index is the
552 // league rank of the team.
553 std::size_t pid = linked_cell_list.permutation( bi + b_offset );
554
555 if ( ( pid >= pid_begin ) && ( pid < pid_end ) )
556 {
557 // Cache the particle coordinates.
558 double x_p = _position( pid, 0 );
559 double y_p = _position( pid, 1 );
560 double z_p = _position( pid, 2 );
561
562 // Loop over the cell stencil.
563 for ( int i = imin; i < imax; ++i )
564 for ( int j = jmin; j < jmax; ++j )
565 for ( int k = kmin; k < kmax; ++k )
566 {
567 // See if we should actually check this box for
568 // neighbors.
569 if ( withinCutoff(
570 pid,
571 linked_cell_list.cellStencil()
572 .grid.minDistanceToPoint(
573 x_p, y_p, z_p, i, j, k ) ) )
574 {
575 // Check the particles in this bin to see if
576 // they are neighbors.
577 std::size_t n_offset =
578 linked_cell_list.binOffset( i, j, k );
579 int num_n =
580 linked_cell_list.binSize( i, j, k );
581 neighbor_for( team, pid, x_p, y_p, z_p,
582 n_offset, num_n,
583 BuildOpTag() );
584 }
585 }
586 }
587 } );
588 }
589
590 // Neighbor fill team vector loop.
591 KOKKOS_INLINE_FUNCTION void
592 neighbor_for( const typename FillNeighborsPolicy::member_type& team,
593 const std::size_t pid, const double x_p, const double y_p,
594 const double z_p, const int n_offset, const int num_n,
595 TeamVectorOpTag ) const
596 {
597 Kokkos::parallel_for(
598 Kokkos::ThreadVectorRange( team, num_n ), [&]( const int n )
599 { neighbor_kernel( pid, x_p, y_p, z_p, n_offset, n ); } );
600 }
601
602 // Neighbor fill serial loop.
603 KOKKOS_INLINE_FUNCTION
604 void neighbor_for( const typename FillNeighborsPolicy::member_type team,
605 const std::size_t pid, const double x_p,
606 const double y_p, const double z_p, const int n_offset,
607 const int num_n, TeamOpTag ) const
608 {
609 for ( int n = 0; n < num_n; n++ )
610 Kokkos::single(
611 Kokkos::PerThread( team ),
612 [&]() { neighbor_kernel( pid, x_p, y_p, z_p, n_offset, n ); } );
613 }
614
615 // Neighbor fill kernel.
616 KOKKOS_INLINE_FUNCTION
617 void neighbor_kernel( const int pid, const double x_p, const double y_p,
618 const double z_p, const int n_offset,
619 const int n ) const
620 {
621 // Get the true id of the candidate neighbor.
622 std::size_t nid = linked_cell_list.permutation( n_offset + n );
623
624 // Cache the candidate neighbor particle coordinates.
625 double x_n = _position( nid, 0 );
626 double y_n = _position( nid, 1 );
627 double z_n = _position( nid, 2 );
628
629 // If this could be a valid neighbor, continue.
631 pid, x_p, y_p, z_p, nid, x_n, y_n, z_n ) )
632 {
633 // Calculate the distance between the particle and its candidate
634 // neighbor.
635 PositionValueType dx = x_p - x_n;
636 PositionValueType dy = y_p - y_n;
637 PositionValueType dz = z_p - z_n;
638 PositionValueType dist_sqr = dx * dx + dy * dy + dz * dz;
639
640 // If within the cutoff increment the neighbor count and add as a
641 // neighbor at that index.
642 addNeighbor( pid, nid, dist_sqr );
643 }
644 }
645};
646
647// Builder creation functions. This is only necessary to define the different
648// random access types.
649template <class DeviceType, class AlgorithmTag, class LayoutTag,
650 class BuildOpTag, class PositionType>
651auto createVerletListBuilder(
652 PositionType x, const std::size_t begin, const std::size_t end,
653 const typename PositionType::value_type radius,
654 const typename PositionType::value_type cell_size_ratio,
655 const typename PositionType::value_type grid_min[3],
656 const typename PositionType::value_type grid_max[3],
657 const std::size_t max_neigh,
658 typename std::enable_if<( is_slice<PositionType>::value ), int>::type* = 0 )
659{
660 using RandomAccessPositionType = typename PositionType::random_access_slice;
661 return VerletListBuilder<DeviceType, RandomAccessPositionType,
662 typename PositionType::value_type, AlgorithmTag,
663 LayoutTag, BuildOpTag>(
664 x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh );
665}
666
667template <class DeviceType, class AlgorithmTag, class LayoutTag,
668 class BuildOpTag, class PositionType>
669auto createVerletListBuilder(
670 PositionType x, const std::size_t begin, const std::size_t end,
671 const typename PositionType::value_type radius,
672 const typename PositionType::value_type cell_size_ratio,
673 const typename PositionType::value_type grid_min[3],
674 const typename PositionType::value_type grid_max[3],
675 const std::size_t max_neigh,
676 typename std::enable_if<( Kokkos::is_view<PositionType>::value ),
677 int>::type* = 0 )
678{
679 using RandomAccessPositionType =
680 Kokkos::View<typename PositionType::value_type**, DeviceType,
681 Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
682 return VerletListBuilder<DeviceType, RandomAccessPositionType,
683 typename PositionType::value_type, AlgorithmTag,
684 LayoutTag, BuildOpTag>(
685 x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh );
686}
687
688template <class DeviceType, class AlgorithmTag, class LayoutTag,
689 class BuildOpTag, class PositionType, class RadiusType>
690auto createVerletListBuilder(
691 PositionType x, const std::size_t begin, const std::size_t end,
692 const typename PositionType::value_type background_radius,
693 const RadiusType radius,
694 const typename PositionType::value_type cell_size_ratio,
695 const typename PositionType::value_type grid_min[3],
696 const typename PositionType::value_type grid_max[3],
697 const std::size_t max_neigh,
698 typename std::enable_if<( is_slice<PositionType>::value ), int>::type* = 0 )
699{
700 using RandomAccessPositionType = typename PositionType::random_access_slice;
701 return VerletListBuilder<DeviceType, RandomAccessPositionType, RadiusType,
702 AlgorithmTag, LayoutTag, BuildOpTag>(
703 x, begin, end, background_radius, radius, cell_size_ratio, grid_min,
704 grid_max, max_neigh );
705}
706
707template <class DeviceType, class AlgorithmTag, class LayoutTag,
708 class BuildOpTag, class PositionType, class RadiusType>
709auto createVerletListBuilder(
710 PositionType x, const std::size_t begin, const std::size_t end,
711 const typename PositionType::value_type background_radius,
712 const RadiusType radius,
713 const typename PositionType::value_type cell_size_ratio,
714 const typename PositionType::value_type grid_min[3],
715 const typename PositionType::value_type grid_max[3],
716 const std::size_t max_neigh,
717 typename std::enable_if<( Kokkos::is_view<PositionType>::value ),
718 int>::type* = 0 )
719{
720 using RandomAccessPositionType =
721 Kokkos::View<typename PositionType::value_type**, DeviceType,
722 Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
723 return VerletListBuilder<DeviceType, RandomAccessPositionType, RadiusType,
724 AlgorithmTag, LayoutTag, BuildOpTag>(
725 x, begin, end, background_radius, radius, cell_size_ratio, grid_min,
726 grid_max, max_neigh );
727}
728
729//---------------------------------------------------------------------------//
730
732} // end namespace Impl
733
734//---------------------------------------------------------------------------//
752template <class MemorySpace, class AlgorithmTag, class LayoutTag,
753 class BuildTag = TeamVectorOpTag>
755{
756 public:
757 static_assert( Kokkos::is_memory_space<MemorySpace>::value, "" );
758
760 using memory_space = MemorySpace;
761
763 using execution_space = typename memory_space::execution_space;
764
767
771 VerletList() = default;
772
807 template <class PositionType>
809 PositionType x, const std::size_t begin, const std::size_t end,
810 const typename PositionType::value_type neighborhood_radius,
811 const typename PositionType::value_type cell_size_ratio,
812 const typename PositionType::value_type grid_min[3],
813 const typename PositionType::value_type grid_max[3],
814 const std::size_t max_neigh = 0,
815 typename std::enable_if<( is_slice<PositionType>::value ||
816 Kokkos::is_view<PositionType>::value ),
817 int>::type* = 0 )
818 {
819 build( x, begin, end, neighborhood_radius, cell_size_ratio, grid_min,
820 grid_max, max_neigh );
821 }
822
859 template <class PositionSlice, class RadiusSlice>
860 VerletList( PositionSlice x, const std::size_t begin, const std::size_t end,
861 const typename PositionSlice::value_type background_radius,
862 RadiusSlice neighborhood_radius,
863 const typename PositionSlice::value_type cell_size_ratio,
864 const typename PositionSlice::value_type grid_min[3],
865 const typename PositionSlice::value_type grid_max[3],
866 const std::size_t max_neigh = 0,
867 typename std::enable_if<( is_slice<PositionSlice>::value ),
868 int>::type* = 0 )
869 {
870 build( x, begin, end, background_radius, neighborhood_radius,
871 cell_size_ratio, grid_min, grid_max, max_neigh );
872 }
873
878 template <class PositionType>
879 void
880 build( PositionType x, const std::size_t begin, const std::size_t end,
881 const typename PositionType::value_type neighborhood_radius,
882 const typename PositionType::value_type cell_size_ratio,
883 const typename PositionType::value_type grid_min[3],
884 const typename PositionType::value_type grid_max[3],
885 const std::size_t max_neigh = 0,
886 typename std::enable_if<( is_slice<PositionType>::value ||
887 Kokkos::is_view<PositionType>::value ),
888 int>::type* = 0 )
889 {
890 // Use the default execution space.
891 build( execution_space{}, x, begin, end, neighborhood_radius,
892 cell_size_ratio, grid_min, grid_max, max_neigh );
893 }
894
898 template <class PositionType, class ExecutionSpace>
899 void
900 build( ExecutionSpace, PositionType x, const std::size_t begin,
901 const std::size_t end,
902 const typename PositionType::value_type neighborhood_radius,
903 const typename PositionType::value_type cell_size_ratio,
904 const typename PositionType::value_type grid_min[3],
905 const typename PositionType::value_type grid_max[3],
906 const std::size_t max_neigh = 0,
907 typename std::enable_if<( is_slice<PositionType>::value ||
908 Kokkos::is_view<PositionType>::value ),
909 int>::type* = 0 )
910 {
911 Kokkos::Profiling::ScopedRegion region( "Cabana::VerletList::build" );
912
914
915 assert( end >= begin );
916 assert( end <= size( x ) );
917
918 using device_type = Kokkos::Device<ExecutionSpace, memory_space>;
919 // Create a builder functor.
920 auto builder = Impl::createVerletListBuilder<device_type, AlgorithmTag,
921 LayoutTag, BuildTag>(
922 x, begin, end, neighborhood_radius, cell_size_ratio, grid_min,
923 grid_max, max_neigh );
924 buildImpl( builder );
925 }
926
931 template <class PositionSlice, class RadiusSlice>
932 void build( PositionSlice x, const std::size_t begin, const std::size_t end,
933 const typename PositionSlice::value_type background_radius,
934 RadiusSlice neighborhood_radius,
935 const typename PositionSlice::value_type cell_size_ratio,
936 const typename PositionSlice::value_type grid_min[3],
937 const typename PositionSlice::value_type grid_max[3],
938 const std::size_t max_neigh = 0 )
939 {
940 // Use the default execution space.
941 build( execution_space{}, x, begin, end, background_radius,
942 neighborhood_radius, cell_size_ratio, grid_min, grid_max,
943 max_neigh );
944 }
945
949 template <class PositionSlice, class RadiusSlice, class ExecutionSpace>
950 void build( ExecutionSpace, PositionSlice x, const std::size_t begin,
951 const std::size_t end,
952 const typename PositionSlice::value_type background_radius,
953 RadiusSlice neighborhood_radius,
954 const typename PositionSlice::value_type cell_size_ratio,
955 const typename PositionSlice::value_type grid_min[3],
956 const typename PositionSlice::value_type grid_max[3],
957 const std::size_t max_neigh = 0 )
958 {
959 Kokkos::Profiling::ScopedRegion region( "Cabana::VerletList::build" );
960
962
963 assert( end >= begin );
964 assert( end <= x.size() );
965
966 // Create a builder functor.
967 using device_type = Kokkos::Device<ExecutionSpace, memory_space>;
968 auto builder = Impl::createVerletListBuilder<device_type, AlgorithmTag,
969 LayoutTag, BuildTag>(
970 x, begin, end, background_radius, neighborhood_radius,
971 cell_size_ratio, grid_min, grid_max, max_neigh );
972 buildImpl( builder );
973 }
974
976 template <class BuilderType>
977 void buildImpl( BuilderType builder )
978 {
979 // For each particle in the range check each neighboring bin for
980 // neighbor particles. Bins are at least the size of the
981 // neighborhood radius so the bin in which the particle resides and
982 // any surrounding bins are guaranteed to contain the neighboring
983 // particles. For CSR lists, we count, then fill neighbors. For 2D
984 // lists, we count and fill at the same time, unless the array size
985 // is exceeded, at which point only counting is continued to
986 // reallocate and refill.
987 typename BuilderType::FillNeighborsPolicy fill_policy(
988 builder.bin_data_1d.numBin(), Kokkos::AUTO, 4 );
989 if ( builder.count )
990 {
991 typename BuilderType::CountNeighborsPolicy count_policy(
992 builder.bin_data_1d.numBin(), Kokkos::AUTO, 4 );
993 Kokkos::parallel_for( "Cabana::VerletList::count_neighbors",
994 count_policy, builder );
995 }
996 else
997 {
998 builder.processCounts( LayoutTag() );
999 Kokkos::parallel_for( "Cabana::VerletList::fill_neighbors",
1000 fill_policy, builder );
1001 }
1002 Kokkos::fence();
1003
1004 // Process the counts by computing offsets and allocating the neighbor
1005 // list, if needed.
1006 builder.processCounts( LayoutTag() );
1007
1008 // For each particle in the range fill (or refill) its part of the
1009 // neighbor list.
1010 if ( builder.count or builder.refill )
1011 {
1012 Kokkos::parallel_for( "Cabana::VerletList::fill_neighbors",
1013 fill_policy, builder );
1014 Kokkos::fence();
1015 }
1016
1017 // Get the data from the builder.
1018 _data = builder._data;
1019 }
1021
1023 KOKKOS_INLINE_FUNCTION
1024 void setNeighbor( const std::size_t particle_index,
1025 const std::size_t neighbor_index,
1026 const int new_index ) const
1027 {
1028 _data.setNeighbor( particle_index, neighbor_index, new_index );
1029 }
1030};
1031
1032//---------------------------------------------------------------------------//
1033// Neighbor list interface implementation.
1034//---------------------------------------------------------------------------//
1036template <class MemorySpace, class AlgorithmTag, class BuildTag>
1038 VerletList<MemorySpace, AlgorithmTag, VerletLayoutCSR, BuildTag>>
1039{
1040 public:
1042 using memory_space = MemorySpace;
1046
1048 KOKKOS_INLINE_FUNCTION
1049 static std::size_t totalNeighbor( const list_type& list )
1050 {
1051 // Size of the allocated memory gives total neighbors.
1052 return list._data.neighbors.extent( 0 );
1053 }
1054
1056 KOKKOS_INLINE_FUNCTION
1057 static std::size_t maxNeighbor( const list_type& list )
1058 {
1059 std::size_t num_p = list._data.counts.size();
1060 return Impl::maxNeighbor( list, num_p );
1061 }
1062
1064 KOKKOS_INLINE_FUNCTION
1065 static std::size_t numNeighbor( const list_type& list,
1066 const std::size_t particle_index )
1067 {
1068 return list._data.counts( particle_index );
1069 }
1070
1073 KOKKOS_INLINE_FUNCTION
1074 static std::size_t getNeighbor( const list_type& list,
1075 const std::size_t particle_index,
1076 const std::size_t neighbor_index )
1077 {
1078 return list._data.neighbors( list._data.offsets( particle_index ) +
1079 neighbor_index );
1080 }
1081};
1082
1083//---------------------------------------------------------------------------//
1085template <class MemorySpace, class AlgorithmTag, class BuildTag>
1087 VerletList<MemorySpace, AlgorithmTag, VerletLayout2D, BuildTag>>
1088{
1089 public:
1091 using memory_space = MemorySpace;
1095
1097 KOKKOS_INLINE_FUNCTION
1098 static std::size_t totalNeighbor( const list_type& list )
1099 {
1100 std::size_t num_p = list._data.counts.size();
1101 return Impl::totalNeighbor( list, num_p );
1102 }
1103
1105 KOKKOS_INLINE_FUNCTION
1106 static std::size_t maxNeighbor( const list_type& list )
1107 {
1108 // Stored during neighbor search.
1109 return list._data.max_n;
1110 }
1111
1113 KOKKOS_INLINE_FUNCTION
1114 static std::size_t numNeighbor( const list_type& list,
1115 const std::size_t particle_index )
1116 {
1117 return list._data.counts( particle_index );
1118 }
1119
1122 KOKKOS_INLINE_FUNCTION
1123 static std::size_t getNeighbor( const list_type& list,
1124 const std::size_t particle_index,
1125 const std::size_t neighbor_index )
1126 {
1127 return list._data.neighbors( particle_index, neighbor_index );
1128 }
1129};
1130
1131//---------------------------------------------------------------------------//
1132
1133} // end namespace Cabana
1134
1135#endif // end CABANA_VERLETLIST_HPP
std::enable_if_t< 3==Array_t::num_space_dim, void > update(Array_t &a, const typename Array_t::value_type alpha, const Array_t &b, const typename Array_t::value_type beta, DecompositionTag tag)
Update two vectors such that a = alpha * a + beta * b. 3D specialization.
Definition Cabana_Grid_Array.hpp:617
KOKKOS_INLINE_FUNCTION std::enable_if_t< 3==SplineDataType::num_space_dim, void > value(const ViewType &view, const SplineDataType &sd, PointDataType &result, typename std::enable_if<(std::rank< PointDataType >::value==0), void * >::type=0)
Interpolate a scalar value to a point. 3D specialization.
Definition Cabana_Grid_Interpolation.hpp:56
Linked cell list binning (spatial sorting) and neighbor iteration.
Neighbor list interface.
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
SIMD and neighbor extension of Kokkos parallel iteration.
Neighborhood discriminator.
Definition Cabana_NeighborList.hpp:55
static KOKKOS_INLINE_FUNCTION std::size_t getNeighbor(const list_type &list, const std::size_t particle_index, const std::size_t neighbor_index)
Definition Cabana_VerletList.hpp:1123
VerletList< MemorySpace, AlgorithmTag, VerletLayout2D, BuildTag > list_type
Neighbor list type.
Definition Cabana_VerletList.hpp:1093
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_VerletList.hpp:1091
static KOKKOS_INLINE_FUNCTION std::size_t numNeighbor(const list_type &list, const std::size_t particle_index)
Get the number of neighbors for a given particle index.
Definition Cabana_VerletList.hpp:1114
static KOKKOS_INLINE_FUNCTION std::size_t totalNeighbor(const list_type &list)
Get the total number of neighbors across all particles.
Definition Cabana_VerletList.hpp:1098
static KOKKOS_INLINE_FUNCTION std::size_t maxNeighbor(const list_type &list)
Get the maximum number of neighbors per particle.
Definition Cabana_VerletList.hpp:1106
static KOKKOS_INLINE_FUNCTION std::size_t numNeighbor(const list_type &list, const std::size_t particle_index)
Get the number of neighbors for a given particle index.
Definition Cabana_VerletList.hpp:1065
VerletList< MemorySpace, AlgorithmTag, VerletLayoutCSR, BuildTag > list_type
Neighbor list type.
Definition Cabana_VerletList.hpp:1044
static KOKKOS_INLINE_FUNCTION std::size_t maxNeighbor(const list_type &list)
Get the maximum number of neighbors across all particles.
Definition Cabana_VerletList.hpp:1057
static KOKKOS_INLINE_FUNCTION std::size_t totalNeighbor(const list_type &list)
Get the total number of neighbors across all particles.
Definition Cabana_VerletList.hpp:1049
static KOKKOS_INLINE_FUNCTION std::size_t getNeighbor(const list_type &list, const std::size_t particle_index, const std::size_t neighbor_index)
Definition Cabana_VerletList.hpp:1074
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_VerletList.hpp:1042
Neighbor list interface. Provides an interface callable at the functor level that gives access to nei...
Definition Cabana_NeighborList.hpp:114
Neighbor operations are executed with team parallelism.
Definition Cabana_Parallel.hpp:206
Neighbor operations are executed with team vector parallelism.
Definition Cabana_Parallel.hpp:211
Neighbor list implementation based on binning particles on a 3d Cartesian grid with cells of the same...
Definition Cabana_VerletList.hpp:755
void build(PositionSlice x, const std::size_t begin, const std::size_t end, const typename PositionSlice::value_type background_radius, RadiusSlice neighborhood_radius, const typename PositionSlice::value_type cell_size_ratio, const typename PositionSlice::value_type grid_min[3], const typename PositionSlice::value_type grid_max[3], const std::size_t max_neigh=0)
Given a list of particle positions and a neighborhood radius calculate the neighbor list.
Definition Cabana_VerletList.hpp:932
VerletListData< memory_space, VerletLayoutCSR > _data
Definition Cabana_VerletList.hpp:766
VerletList(PositionType x, const std::size_t begin, const std::size_t end, const typename PositionType::value_type neighborhood_radius, const typename PositionType::value_type cell_size_ratio, const typename PositionType::value_type grid_min[3], const typename PositionType::value_type grid_max[3], const std::size_t max_neigh=0, typename std::enable_if<(is_slice< PositionType >::value||Kokkos::is_view< PositionType >::value), int >::type *=0)
VerletList constructor. Given a list of particle positions and a neighborhood radius calculate the ne...
Definition Cabana_VerletList.hpp:808
KOKKOS_INLINE_FUNCTION void setNeighbor(const std::size_t particle_index, const std::size_t neighbor_index, const int new_index) const
Modify a neighbor in the list; for example, mark it as a broken bond.
Definition Cabana_VerletList.hpp:1024
VerletList()=default
Default constructor.
typename memory_space::execution_space execution_space
Kokkos default execution space for this memory space.
Definition Cabana_VerletList.hpp:763
void build(ExecutionSpace, PositionType x, const std::size_t begin, const std::size_t end, const typename PositionType::value_type neighborhood_radius, const typename PositionType::value_type cell_size_ratio, const typename PositionType::value_type grid_min[3], const typename PositionType::value_type grid_max[3], const std::size_t max_neigh=0, typename std::enable_if<(is_slice< PositionType >::value||Kokkos::is_view< PositionType >::value), int >::type *=0)
Given a list of particle positions and a neighborhood radius calculate the neighbor list.
Definition Cabana_VerletList.hpp:900
MemorySpace memory_space
Kokkos memory space in which the neighbor list data resides.
Definition Cabana_VerletList.hpp:760
void build(ExecutionSpace, PositionSlice x, const std::size_t begin, const std::size_t end, const typename PositionSlice::value_type background_radius, RadiusSlice neighborhood_radius, const typename PositionSlice::value_type cell_size_ratio, const typename PositionSlice::value_type grid_min[3], const typename PositionSlice::value_type grid_max[3], const std::size_t max_neigh=0)
Given a list of particle positions and a neighborhood radius calculate the neighbor list.
Definition Cabana_VerletList.hpp:950
VerletList(PositionSlice x, const std::size_t begin, const std::size_t end, const typename PositionSlice::value_type background_radius, RadiusSlice neighborhood_radius, const typename PositionSlice::value_type cell_size_ratio, const typename PositionSlice::value_type grid_min[3], const typename PositionSlice::value_type grid_max[3], const std::size_t max_neigh=0, typename std::enable_if<(is_slice< PositionSlice >::value), int >::type *=0)
VerletList constructor. Given a list of particle positions and a neighborhood radius calculate the ne...
Definition Cabana_VerletList.hpp:860
void build(PositionType x, const std::size_t begin, const std::size_t end, const typename PositionType::value_type neighborhood_radius, const typename PositionType::value_type cell_size_ratio, const typename PositionType::value_type grid_min[3], const typename PositionType::value_type grid_max[3], const std::size_t max_neigh=0, typename std::enable_if<(is_slice< PositionType >::value||Kokkos::is_view< PositionType >::value), int >::type *=0)
Definition Cabana_VerletList.hpp:880
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
2D array neighbor list layout.
Definition Cabana_VerletList.hpp:40
CSR (compressed sparse row) neighbor list layout.
Definition Cabana_VerletList.hpp:35
KOKKOS_INLINE_FUNCTION void addNeighbor(const int pid, const int nid) const
Add a neighbor to the list.
Definition Cabana_VerletList.hpp:100
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_VerletList.hpp:86
Kokkos::View< int *, memory_space > counts
Number of neighbors per particle.
Definition Cabana_VerletList.hpp:89
Kokkos::View< int **, memory_space > neighbors
Neighbor list.
Definition Cabana_VerletList.hpp:92
KOKKOS_INLINE_FUNCTION void setNeighbor(const int pid, const int nid, const int new_id) const
Modify a neighbor in the list.
Definition Cabana_VerletList.hpp:109
std::size_t max_n
Definition Cabana_VerletList.hpp:96
KOKKOS_INLINE_FUNCTION void setNeighbor(const int pid, const int nid, const int new_id) const
Modify a neighbor in the list.
Definition Cabana_VerletList.hpp:75
Kokkos::View< int *, memory_space > offsets
Offsets into the neighbor list.
Definition Cabana_VerletList.hpp:60
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_VerletList.hpp:54
Kokkos::View< int *, memory_space > counts
Number of neighbors per particle.
Definition Cabana_VerletList.hpp:57
KOKKOS_INLINE_FUNCTION void addNeighbor(const int pid, const int nid) const
Add a neighbor to the list.
Definition Cabana_VerletList.hpp:67
Kokkos::View< int *, memory_space > neighbors
Neighbor list.
Definition Cabana_VerletList.hpp:63
Definition Cabana_VerletList.hpp:47
Definition Cabana_Types.hpp:88
Slice static type checker.
Definition Cabana_Slice.hpp:861