diff --git a/core/src/Cabana_Experimental_NeighborList.hpp b/core/src/Cabana_Experimental_NeighborList.hpp index ddab1d7e6..25e874b3c 100644 --- a/core/src/Cabana_Experimental_NeighborList.hpp +++ b/core/src/Cabana_Experimental_NeighborList.hpp @@ -46,29 +46,33 @@ using remove_cvref_t = typename remove_cvref::type; namespace Impl { -template ::value>> -struct SubsliceAndRadius +template ::value || + Kokkos::is_view_v>> +struct SubPositionsAndRadius { - using slice_type = Slice; - using memory_space = typename Slice::memory_space; - Slice slice; - using size_type = typename Slice::size_type; + using positions_type = Positions; + using memory_space = typename Positions::memory_space; + Positions data; + using size_type = typename Positions::size_type; size_type first; size_type last; - using value_type = typename Slice::value_type; + using value_type = typename Positions::value_type; value_type radius; }; -template >::value>> +template >::value || + Kokkos::is_view_v>> auto makePredicates( - Slice&& slice, typename stdcxx20::remove_cvref_t::size_type first, - typename stdcxx20::remove_cvref_t::size_type last, - typename stdcxx20::remove_cvref_t::value_type radius ) + Positions&& positions, + typename stdcxx20::remove_cvref_t::size_type first, + typename stdcxx20::remove_cvref_t::size_type last, + typename stdcxx20::remove_cvref_t::value_type radius ) { - return Impl::SubsliceAndRadius>{ - std::forward( slice ), first, last, radius }; + return Impl::SubPositionsAndRadius>{ + std::forward( positions ), first, last, radius }; } template @@ -100,19 +104,23 @@ max_reduce( ExecutionSpace const& space, Kokkos::View const& v ) namespace ArborX { -//! Neighbor access trait for Cabana slice. -template -struct AccessTraits{}>> +//! Neighbor access trait for Cabana slice and/or Kokkos View. +template +struct AccessTraits{} || + Kokkos::is_view{}>> { //! Kokkos memory space. - using memory_space = typename Slice::memory_space; + using memory_space = typename Positions::memory_space; //! Size type. - using size_type = typename Slice::size_type; - //! Get number of particles in the slice. - static KOKKOS_FUNCTION size_type size( Slice const& x ) { return x.size(); } + using size_type = typename Positions::size_type; + //! Get number of particles. + static KOKKOS_FUNCTION size_type size( Positions const& x ) + { + return Cabana::size( x ); + } //! Get the particle at the index. - static KOKKOS_FUNCTION Point get( Slice const& x, size_type i ) + static KOKKOS_FUNCTION Point get( Positions const& x, size_type i ) { return { static_cast( x( i, 0 ) ), static_cast( x( i, 1 ) ), @@ -120,28 +128,29 @@ struct AccessTraits -struct AccessTraits, - PredicatesTag> +template +struct AccessTraits< + Cabana::Experimental::Impl::SubPositionsAndRadius, PredicatesTag> { - //! Slice wrapper with partial range and radius information. - using SliceLike = Cabana::Experimental::Impl::SubsliceAndRadius; + //! Position wrapper with partial range and radius information. + using PositionLike = + Cabana::Experimental::Impl::SubPositionsAndRadius; //! Kokkos memory space. - using memory_space = typename SliceLike::memory_space; + using memory_space = typename PositionLike::memory_space; //! Size type. - using size_type = typename SliceLike::size_type; + using size_type = typename PositionLike::size_type; //! Get number of particles. - static KOKKOS_FUNCTION size_type size( SliceLike const& x ) + static KOKKOS_FUNCTION size_type size( PositionLike const& x ) { return x.last - x.first; } //! Get the particle at the index. - static KOKKOS_FUNCTION auto get( SliceLike const& x, size_type i ) + static KOKKOS_FUNCTION auto get( PositionLike const& x, size_type i ) { assert( i < size( x ) ); auto const point = - AccessTraits::get( - x.slice, x.first + i ); + AccessTraits::get( x.data, x.first + i ); return attach( intersects( Sphere{ point, x.radius } ), (int)i ); } }; @@ -282,12 +291,12 @@ struct CrsGraph interaction distance with a 1D compressed layout for particles and neighbors. \tparam ExecutionSpace Kokkos execution space. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam AlgorithmTag Tag indicating whether to build a full or half neighbor list. \param space Kokkos execution space. - \param coordinate_slice The slice containing the particle positions. + \param positions The particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -297,26 +306,27 @@ struct CrsGraph Neighbor list implementation most appropriate for highly varying particle densities. */ -template -auto makeNeighborList( ExecutionSpace space, Tag, Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, int buffer_size = 0 ) +template +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 ) { assert( buffer_size >= 0 ); assert( last >= first ); - assert( last <= coordinate_slice.size() ); + assert( last <= positions.size() ); - using memory_space = typename Slice::memory_space; + using memory_space = typename Positions::memory_space; - ArborX::BVH bvh( space, coordinate_slice ); + ArborX::BVH bvh( space, positions ); Kokkos::View indices( Kokkos::view_alloc( "indices", Kokkos::WithoutInitializing ), 0 ); Kokkos::View offset( Kokkos::view_alloc( "offset", Kokkos::WithoutInitializing ), 0 ); bvh.query( - space, Impl::makePredicates( coordinate_slice, first, last, radius ), + space, Impl::makePredicates( positions, first, last, radius ), Impl::NeighborDiscriminatorCallback{}, indices, offset, ArborX::Experimental::TraversalPolicy().setBufferSize( buffer_size ) ); @@ -328,11 +338,11 @@ auto makeNeighborList( ExecutionSpace space, Tag, Slice const& coordinate_slice, \brief Neighbor list implementation using ArborX for particles within the interaction distance with a 1D compressed layout for particles and neighbors. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam Tag Tag indicating whether to build a full or half neighbor list. \param tag Tag indicating whether to build a full or half neighbor list. - \param coordinate_slice The slice containing the particle positions. + \param positions The containing the particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -342,14 +352,15 @@ auto makeNeighborList( ExecutionSpace space, Tag, Slice const& coordinate_slice, Neighbor list implementation most appropriate for highly varying particle densities. */ -template -auto makeNeighborList( Tag tag, Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, int buffer_size = 0 ) +template +auto makeNeighborList( Tag tag, Positions const& positions, + typename Positions::size_type first, + typename Positions::size_type last, + typename Positions::value_type radius, + int buffer_size = 0 ) { - typename Slice::execution_space space{}; - return makeNeighborList( space, tag, coordinate_slice, first, last, radius, + typename Positions::execution_space space{}; + return makeNeighborList( space, tag, positions, first, last, radius, buffer_size ); } @@ -358,11 +369,11 @@ auto makeNeighborList( Tag tag, Slice const& coordinate_slice, interaction distance with a 1D compressed layout for particles and neighbors. \tparam DeviceType Kokkos device type. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam Tag Tag indicating whether to build a full or half neighbor list. \param tag Tag indicating whether to build a full or half neighbor list. - \param coordinate_slice The slice containing the particle positions. + \param positions The particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -372,16 +383,16 @@ auto makeNeighborList( Tag tag, Slice const& coordinate_slice, Neighbor list implementation most appropriate for highly varying particle densities. */ -template -[[deprecated]] auto makeNeighborList( Tag tag, Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, +template +[[deprecated]] auto makeNeighborList( Tag tag, Positions const& positions, + typename Positions::size_type first, + typename Positions::size_type last, + typename Positions::value_type radius, int buffer_size = 0 ) { using exec_space = typename DeviceType::execution_space; - return makeNeighborList( exec_space{}, tag, coordinate_slice, first, last, - radius, buffer_size ); + return makeNeighborList( exec_space{}, tag, positions, first, last, radius, + buffer_size ); } //---------------------------------------------------------------------------// @@ -405,11 +416,11 @@ struct Dense interaction distance with a 2D layout for particles and neighbors. \tparam ExecutionSpace Kokkos execution space. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam Tag Tag indicating whether to build a full or half neighbor list. \param space Kokkos execution space. - \param coordinate_slice The slice containing the particle positions. + \param positions The particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -420,24 +431,23 @@ struct Dense Neighbor list implementation most appropriate for highly varying particle densities. */ -template -auto make2DNeighborList( ExecutionSpace space, Tag, - Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, +template +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 ) { assert( buffer_size >= 0 ); assert( last >= first ); - assert( last <= coordinate_slice.size() ); + assert( last <= positions.size() ); - using memory_space = typename Slice::memory_space; + using memory_space = typename Positions::memory_space; - ArborX::BVH bvh( space, coordinate_slice ); + ArborX::BVH bvh( space, positions ); auto const predicates = - Impl::makePredicates( coordinate_slice, first, last, radius ); + Impl::makePredicates( positions, first, last, radius ); auto const n_queries = ArborX::AccessTraits, @@ -490,11 +500,11 @@ auto make2DNeighborList( ExecutionSpace space, Tag, \brief Neighbor list implementation using ArborX for particles within the interaction distance with a 2D layout for particles and neighbors. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam Tag Tag indicating whether to build a full or half neighbor list. \param tag Tag indicating whether to build a full or half neighbor list. - \param coordinate_slice The slice containing the particle positions. + \param positions The particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -505,15 +515,15 @@ auto make2DNeighborList( ExecutionSpace space, Tag, Neighbor list implementation most appropriate for highly varying particle densities. */ -template -auto make2DNeighborList( Tag tag, Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, +template +auto make2DNeighborList( Tag tag, Positions const& positions, + typename Positions::size_type first, + typename Positions::size_type last, + typename Positions::value_type radius, int buffer_size = 0 ) { - using exec_space = typename Slice::execution_space; - return make2DNeighborList( exec_space{}, tag, coordinate_slice, first, last, + using exec_space = typename Positions::execution_space; + return make2DNeighborList( exec_space{}, tag, positions, first, last, radius, buffer_size ); } @@ -522,11 +532,11 @@ auto make2DNeighborList( Tag tag, Slice const& coordinate_slice, interaction distance with a 2D layout for particles and neighbors. \tparam DeviceType Kokkos device type. - \tparam Slice The position slice type. + \tparam Positions The position type. \tparam Tag Tag indicating whether to build a full or half neighbor list. \param tag Tag indicating whether to build a full or half neighbor list. - \param coordinate_slice The slice containing the particle positions. + \param positions The particle positions. \param first The beginning particle index to compute neighbors for. \param last The end particle index to compute neighbors for. \param radius The radius of the neighborhood. Particles within this radius are @@ -537,15 +547,15 @@ auto make2DNeighborList( Tag tag, Slice const& coordinate_slice, Neighbor list implementation most appropriate for highly varying particle densities. */ -template -[[deprecated]] auto make2DNeighborList( Tag tag, Slice const& coordinate_slice, - typename Slice::size_type first, - typename Slice::size_type last, - typename Slice::value_type radius, +template +[[deprecated]] auto make2DNeighborList( Tag tag, Positions const& positions, + typename Positions::size_type first, + typename Positions::size_type last, + typename Positions::value_type radius, int buffer_size = 0 ) { using exec_space = typename DeviceType::execution_space; - return make2DNeighborList( exec_space{}, tag, coordinate_slice, first, last, + return make2DNeighborList( exec_space{}, tag, positions, first, last, radius, buffer_size ); } diff --git a/core/src/Cabana_LinkedCellList.hpp b/core/src/Cabana_LinkedCellList.hpp index c771928a6..f38c556e6 100644 --- a/core/src/Cabana_LinkedCellList.hpp +++ b/core/src/Cabana_LinkedCellList.hpp @@ -123,39 +123,41 @@ class LinkedCellList LinkedCellList() {} /*! - \brief Slice constructor + \brief Simple constructor - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param grid_delta Grid sizes in each cardinal direction. \param grid_min Grid minimum value in each direction. \param grid_max Grid maximum value in each direction. */ - template - LinkedCellList( SliceType positions, const Scalar grid_delta[3], - const Scalar grid_min[3], const Scalar grid_max[3], - typename std::enable_if<( is_slice::value ), - int>::type* = 0 ) + template + LinkedCellList( + PositionType positions, const Scalar grid_delta[3], + const Scalar grid_min[3], const Scalar grid_max[3], + typename std::enable_if<( is_slice::value || + Kokkos::is_view::value ), + int>::type* = 0 ) : _begin( 0 ) - , _end( positions.size() ) + , _end( size( positions ) ) , _grid( grid_min[0], grid_min[1], grid_min[2], grid_max[0], grid_max[1], grid_max[2], grid_delta[0], grid_delta[1], grid_delta[2] ) , _cell_stencil( grid_delta[0], 1.0, grid_min, grid_max ) , _sorted( false ) { - std::size_t np = positions.size(); + std::size_t np = size( positions ); allocate( totalBins(), np ); build( positions, 0, np ); } /*! - \brief Slice constructor + \brief Partial range constructor - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param begin The beginning index of particles to bin or find neighbors for. Particles outside this range will NOT be considered as candidate neighbors. @@ -166,12 +168,14 @@ class LinkedCellList \param grid_min Grid minimum value in each direction. \param grid_max Grid maximum value in each direction. */ - template - LinkedCellList( SliceType positions, const std::size_t begin, - const std::size_t end, const Scalar grid_delta[3], - const Scalar grid_min[3], const Scalar grid_max[3], - typename std::enable_if<( is_slice::value ), - int>::type* = 0 ) + template + LinkedCellList( + PositionType positions, const std::size_t begin, const std::size_t end, + const Scalar grid_delta[3], const Scalar grid_min[3], + const Scalar grid_max[3], + typename std::enable_if<( is_slice::value || + Kokkos::is_view::value ), + int>::type* = 0 ) : _begin( begin ) , _end( end ) , _grid( grid_min[0], grid_min[1], grid_min[2], grid_max[0], @@ -185,26 +189,27 @@ class LinkedCellList } /*! - \brief Slice constructor + \brief Explicit stencil constructor - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param grid_delta Grid sizes in each cardinal direction. \param grid_min Grid minimum value in each direction. \param grid_max Grid maximum value in each direction. \param neighborhood_radius Radius for neighbors. \param cell_size_ratio Ratio of the cell size to the neighborhood size. */ - template + template LinkedCellList( - SliceType positions, const Scalar grid_delta[3], + PositionType positions, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3], const Scalar neighborhood_radius, const Scalar cell_size_ratio = 1, - typename std::enable_if<( is_slice::value ), int>::type* = - 0 ) + typename std::enable_if<( is_slice::value || + Kokkos::is_view::value ), + int>::type* = 0 ) : _begin( 0 ) - , _end( positions.size() ) + , _end( size( positions ) ) , _grid( grid_min[0], grid_min[1], grid_min[2], grid_max[0], grid_max[1], grid_max[2], grid_delta[0], grid_delta[1], grid_delta[2] ) @@ -212,17 +217,17 @@ class LinkedCellList grid_max ) , _sorted( false ) { - std::size_t np = positions.size(); + std::size_t np = size( positions ); allocate( totalBins(), np ); build( positions, 0, np ); } /*! - \brief Slice range constructor + \brief Explicit stencil and partial range constructor - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param begin The beginning index of particles to bin or find neighbors for. Particles outside this range will NOT be considered as candidate neighbors. @@ -235,14 +240,15 @@ class LinkedCellList \param neighborhood_radius Radius for neighbors. \param cell_size_ratio Ratio of the cell size to the neighborhood size. */ - template + template LinkedCellList( - SliceType positions, const std::size_t begin, const std::size_t end, + PositionType positions, const std::size_t begin, const std::size_t end, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3], const Scalar neighborhood_radius, const Scalar cell_size_ratio = 1, - typename std::enable_if<( is_slice::value ), int>::type* = - 0 ) + typename std::enable_if<( is_slice::value || + Kokkos::is_view::value ), + int>::type* = 0 ) : _begin( begin ) , _end( end ) , _grid( grid_min[0], grid_min[1], grid_min[2], grid_max[0], @@ -382,9 +388,9 @@ class LinkedCellList \brief Build the linked cell list with a subset of particles. \tparam ExecutionSpace Kokkos execution space. - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param begin The beginning index of particles to bin or find neighbors for. Particles outside this range will NOT be considered as candidate neighbors. @@ -392,8 +398,8 @@ class LinkedCellList for. Particles outside this range will NOT be considered as candidate neighbors. */ - template - void build( ExecutionSpace, SliceType positions, const std::size_t begin, + template + void build( ExecutionSpace, PositionType positions, const std::size_t begin, const std::size_t end ) { Kokkos::Profiling::ScopedRegion region( @@ -401,7 +407,7 @@ class LinkedCellList static_assert( is_accessible_from{}, "" ); assert( end >= begin ); - assert( end <= positions.size() ); + assert( end <= size( positions ) ); // Resize the binning data. Note that the permutation vector spans // only the length of begin-end; @@ -481,9 +487,9 @@ class LinkedCellList /*! \brief Build the linked cell list with a subset of particles. - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. \param begin The beginning index of particles to bin or find neighbors for. Particles outside this range will NOT be considered as candidate neighbors. @@ -491,8 +497,8 @@ class LinkedCellList for. Particles outside this range will NOT be considered as candidate neighbors. */ - template - void build( SliceType positions, const std::size_t begin, + template + void build( PositionType positions, const std::size_t begin, const std::size_t end ) { // Use the default execution space. @@ -502,14 +508,14 @@ class LinkedCellList /*! \brief Build the linked cell list with all particles. - \tparam SliceType Slice type for positions. + \tparam PositionType Type for positions. - \param positions Slice of positions. + \param positions Particle positions. */ - template - void build( SliceType positions ) + template + void build( PositionType positions ) { - build( positions, 0, positions.size() ); + build( positions, 0, size( positions ) ); } /*! @@ -640,8 +646,8 @@ class LinkedCellList \brief Creation function for linked cell list. \return LinkedCellList. */ -template -auto createLinkedCellList( SliceType positions, const Scalar grid_delta[3], +template +auto createLinkedCellList( PositionType positions, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3] ) { return LinkedCellList( positions, grid_delta, grid_min, @@ -652,8 +658,8 @@ auto createLinkedCellList( SliceType positions, const Scalar grid_delta[3], \brief Creation function for linked cell list with partial range. \return LinkedCellList. */ -template -auto createLinkedCellList( SliceType positions, const std::size_t begin, +template +auto createLinkedCellList( PositionType positions, const std::size_t begin, const std::size_t end, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3] ) { @@ -666,8 +672,8 @@ auto createLinkedCellList( SliceType positions, const std::size_t begin, cell ratio. \return LinkedCellList. */ -template -auto createLinkedCellList( SliceType positions, const Scalar grid_delta[3], +template +auto createLinkedCellList( PositionType positions, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3], const Scalar neighborhood_radius, const Scalar cell_size_ratio = 1.0 ) @@ -682,8 +688,8 @@ auto createLinkedCellList( SliceType positions, const Scalar grid_delta[3], cutoff radius and/or cell ratio. \return LinkedCellList. */ -template -auto createLinkedCellList( SliceType positions, const std::size_t begin, +template +auto createLinkedCellList( PositionType positions, const std::size_t begin, const std::size_t end, const Scalar grid_delta[3], const Scalar grid_min[3], const Scalar grid_max[3], const Scalar neighborhood_radius, @@ -717,51 +723,26 @@ struct is_linked_cell_list //---------------------------------------------------------------------------// /*! - \brief Given a linked cell list permute an AoSoA. - - \tparam LinkedCellListType The linked cell list type. - - \tparam AoSoA_t The AoSoA type. - - \param linked_cell_list The linked cell list to permute the AoSoA with. - - \param aosoa The AoSoA to permute. - */ -template -void permute( - LinkedCellListType& linked_cell_list, AoSoA_t& aosoa, - typename std::enable_if<( is_linked_cell_list::value && - is_aosoa::value ), - int>::type* = 0 ) -{ - permute( linked_cell_list.binningData(), aosoa ); - - // Update internal state. - linked_cell_list.update( true ); - - linked_cell_list.storeParticleBins(); -} - -//---------------------------------------------------------------------------// -/*! - \brief Given a linked cell list permute a slice. + \brief Given a linked cell list permute positions. \tparam LinkedCellListType The linked cell list type. - \tparam SliceType The slice type. + \tparam PositionType Positions type (AoSoA or Slice or Kokkos::View). - \param linked_cell_list The linked cell list to permute the slice with. + \param linked_cell_list The linked cell list to permute the positions with. - \param slice The slice to permute. + \param positions Positions to permute. */ -template +template void permute( - LinkedCellListType& linked_cell_list, SliceType& slice, + LinkedCellListType& linked_cell_list, PositionType& positions, typename std::enable_if<( is_linked_cell_list::value && - is_slice::value ), + ( is_aosoa::value || + is_slice::value || + Kokkos::is_view::value ) ), int>::type* = 0 ) { - permute( linked_cell_list.binningData(), slice ); + permute( linked_cell_list.binningData(), positions ); // Update internal state. linked_cell_list.update( true ); diff --git a/core/src/Cabana_Slice.hpp b/core/src/Cabana_Slice.hpp index 5954800b6..8fa335401 100644 --- a/core/src/Cabana_Slice.hpp +++ b/core/src/Cabana_Slice.hpp @@ -927,7 +927,7 @@ void copySliceToView( ViewType& view, const SliceType& slice, // Copy from View. //---------------------------------------------------------------------------// -//! Copy from slice to View. Rank-0 +//! Copy from View to slice. Rank-0 template void copyViewToSlice( ExecutionSpace exec_space, SliceType& slice, const ViewType& view, @@ -941,7 +941,7 @@ void copyViewToSlice( KOKKOS_LAMBDA( const int i ) { slice( i - begin ) = view( i ); } ); } -//! Copy from slice to View. Rank-1 +//! Copy from View to slice. Rank-1 template void copyViewToSlice( ExecutionSpace exec_space, SliceType& slice, const ViewType& view, @@ -958,7 +958,7 @@ void copyViewToSlice( } ); } -//! Copy from slice to View. Rank-2 +//! Copy from View to slice. Rank-2 template void copyViewToSlice( ExecutionSpace exec_space, SliceType& slice, const ViewType& view, @@ -976,13 +976,13 @@ void copyViewToSlice( } ); } -//! Copy from slice to View with default execution space. +//! Copy from View to slice with default execution space. template -void copyViewToSlice( ViewType& view, const SliceType& slice, +void copyViewToSlice( SliceType& slice, const ViewType& view, const std::size_t begin, const std::size_t end ) { using exec_space = typename SliceType::execution_space; - copyViewToSlice( exec_space{}, view, slice, begin, end ); + copyViewToSlice( exec_space{}, slice, view, begin, end ); } //! Check slice size (differs from Kokkos View). @@ -1007,6 +1007,23 @@ void checkSize( //---------------------------------------------------------------------------// +//! Check slice size (differs from Kokkos View). +template +auto size( SliceType slice, + typename std::enable_if::value, int>::type* = 0 ) +{ + return slice.size(); +} + +//! Check View size (differs from Slice). +template +auto size( + ViewType view, + typename std::enable_if::value, int>::type* = 0 ) +{ + return view.extent( 0 ); +} + } // end namespace Cabana //---------------------------------------------------------------------------// diff --git a/core/src/Cabana_Sort.hpp b/core/src/Cabana_Sort.hpp index 938a220e7..fbec5ac3a 100644 --- a/core/src/Cabana_Sort.hpp +++ b/core/src/Cabana_Sort.hpp @@ -660,6 +660,64 @@ void permute( Kokkos::fence(); } +//---------------------------------------------------------------------------// +/*! + \brief Given binning data permute a View. + + \tparam BinningDataType The binning data type. + + \tparam ViewType The view type. + + \param binning_data The binning data. + + \param view The view to permute. + */ +template +void permute( + const BinningDataType& binning_data, ViewType& view, + typename std::enable_if<( is_binning_data::value && + Kokkos::is_view::value ), + int>::type* = 0 ) +{ + Kokkos::Profiling::pushRegion( "Cabana::permute" ); + + auto begin = binning_data.rangeBegin(); + auto end = binning_data.rangeEnd(); + + // Get the number of components (1 for View). + std::size_t num_comp = 1; + for ( std::size_t d = 1; d < view.rank; ++d ) + num_comp *= view.extent( d ); + + Kokkos::View scratch( + Kokkos::ViewAllocateWithoutInitializing( "scratch" ), end - begin, + num_comp ); + + auto permute_to_scratch = KOKKOS_LAMBDA( const std::size_t i ) + { + auto permute_i = binning_data.permutation( i - begin ); + for ( std::size_t n = 0; n < num_comp; ++n ) + scratch( i - begin, n ) = view( permute_i, n ); + }; + auto policy = + Kokkos::RangePolicy( begin, end ); + Kokkos::parallel_for( "Cabana::kokkosBinSort::permute_to_scratch", policy, + permute_to_scratch ); + Kokkos::fence(); + + auto copy_back = KOKKOS_LAMBDA( const std::size_t i ) + { + for ( std::size_t n = 0; n < num_comp; ++n ) + view( i, n ) = scratch( i - begin, n ); + }; + Kokkos::parallel_for( "Cabana::kokkosBinSort::copy_back", policy, + copy_back ); + Kokkos::fence(); + + Kokkos::Profiling::popRegion(); +} + //---------------------------------------------------------------------------// } // end namespace Cabana diff --git a/core/src/Cabana_VerletList.hpp b/core/src/Cabana_VerletList.hpp index eb3dcfcdb..2741534cd 100644 --- a/core/src/Cabana_VerletList.hpp +++ b/core/src/Cabana_VerletList.hpp @@ -123,15 +123,13 @@ namespace Impl //---------------------------------------------------------------------------// // Verlet List Builder //---------------------------------------------------------------------------// -template +template struct VerletListBuilder { // Types. using device = DeviceType; - using PositionValueType = typename PositionSlice::value_type; - using RandomAccessPositionSlice = - typename PositionSlice::random_access_slice; + using PositionValueType = typename PositionType::value_type; using memory_space = typename device::memory_space; using execution_space = typename device::execution_space; @@ -142,7 +140,7 @@ struct VerletListBuilder PositionValueType rsqr; // Positions. - RandomAccessPositionSlice position; + RandomAccessPositionType _position; std::size_t pid_begin, pid_end; // Binning Data. @@ -157,7 +155,7 @@ struct VerletListBuilder std::size_t alloc_n; // Constructor. - VerletListBuilder( PositionSlice slice, const std::size_t begin, + VerletListBuilder( PositionType positions, const std::size_t begin, const std::size_t end, const PositionValueType neighborhood_radius, const PositionValueType cell_size_ratio, @@ -172,14 +170,14 @@ struct VerletListBuilder refill = false; // Create the count view. - _data.counts = - Kokkos::View( "num_neighbors", slice.size() ); + _data.counts = Kokkos::View( "num_neighbors", + size( positions ) ); // Make a guess for the number of neighbors per particle for 2D lists. initCounts( LayoutTag() ); - // Get the positions with random access read-only memory. - position = slice; + // Shallow copy for random access read-only memory. + _position = positions; // Bin the particles in the grid. Don't actually sort them but make a // permutation vector. Note that we are binning all particles here and @@ -188,7 +186,7 @@ struct VerletListBuilder double grid_size = cell_size_ratio * neighborhood_radius; PositionValueType grid_delta[3] = { grid_size, grid_size, grid_size }; linked_cell_list = createLinkedCellList( - position, grid_delta, grid_min, grid_max, neighborhood_radius, + _position, grid_delta, grid_min, grid_max, neighborhood_radius, cell_size_ratio ); bin_data_1d = linked_cell_list.binningData(); @@ -232,9 +230,9 @@ struct VerletListBuilder if ( ( pid >= pid_begin ) && ( pid < pid_end ) ) { // Cache the particle coordinates. - double x_p = position( pid, 0 ); - double y_p = position( pid, 1 ); - double z_p = position( pid, 2 ); + double x_p = _position( pid, 0 ); + double y_p = _position( pid, 1 ); + double z_p = _position( pid, 2 ); // Loop over the cell stencil. int stencil_count = 0; @@ -306,9 +304,9 @@ struct VerletListBuilder std::size_t nid = linked_cell_list.permutation( n_offset + n ); // Cache the candidate neighbor particle coordinates. - double x_n = position( nid, 0 ); - double y_n = position( nid, 1 ); - double z_n = position( nid, 2 ); + double x_n = _position( nid, 0 ); + double y_n = _position( nid, 1 ); + double z_n = _position( nid, 2 ); // If this could be a valid neighbor, continue. if ( NeighborDiscriminator::isValid( @@ -450,9 +448,9 @@ struct VerletListBuilder if ( ( pid >= pid_begin ) && ( pid < pid_end ) ) { // Cache the particle coordinates. - double x_p = position( pid, 0 ); - double y_p = position( pid, 1 ); - double z_p = position( pid, 2 ); + double x_p = _position( pid, 0 ); + double y_p = _position( pid, 1 ); + double z_p = _position( pid, 2 ); // Loop over the cell stencil. for ( int i = imin; i < imax; ++i ) @@ -515,9 +513,9 @@ struct VerletListBuilder std::size_t nid = linked_cell_list.permutation( n_offset + n ); // Cache the candidate neighbor particle coordinates. - double x_n = position( nid, 0 ); - double y_n = position( nid, 1 ); - double z_n = position( nid, 2 ); + double x_n = _position( nid, 0 ); + double y_n = _position( nid, 1 ); + double z_n = _position( nid, 2 ); // If this could be a valid neighbor, continue. if ( NeighborDiscriminator::isValid( @@ -540,6 +538,45 @@ struct VerletListBuilder } }; +// Builder creation functions. This is only necessary to define the different +// random access types. +template +auto createVerletListBuilder( + PositionType x, const std::size_t begin, const std::size_t end, + const typename PositionType::value_type 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, + typename std::enable_if<( is_slice::value ), int>::type* = 0 ) +{ + using RandomAccessPositionType = typename PositionType::random_access_slice; + return VerletListBuilder( + x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh ); +} + +template +auto createVerletListBuilder( + PositionType x, const std::size_t begin, const std::size_t end, + const typename PositionType::value_type 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, + typename std::enable_if<( Kokkos::is_view::value ), + int>::type* = 0 ) +{ + using RandomAccessPositionType = + Kokkos::View>; + return VerletListBuilder( + x, begin, end, radius, cell_size_ratio, grid_min, grid_max, max_neigh ); +} + //---------------------------------------------------------------------------// //! \endcond @@ -588,7 +625,7 @@ class VerletList \brief VerletList constructor. Given a list of particle positions and a neighborhood radius calculate the neighbor list. - \param x The slice containing the particle positions + \param x The particle positions \param begin The beginning particle index to compute neighbors for. @@ -618,15 +655,17 @@ class VerletList range. All particles are candidates for being a neighbor, regardless of whether or not they are in the range. */ - template - VerletList( PositionSlice x, const std::size_t begin, const std::size_t end, - const typename PositionSlice::value_type 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::value ), - int>::type* = 0 ) + template + 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::value || + Kokkos::is_view::value ), + int>::type* = 0 ) { build( x, begin, end, neighborhood_radius, cell_size_ratio, grid_min, grid_max, max_neigh ); @@ -636,13 +675,17 @@ class VerletList \brief Given a list of particle positions and a neighborhood radius calculate the neighbor list. */ - template - void build( PositionSlice x, const std::size_t begin, const std::size_t end, - const typename PositionSlice::value_type 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 ) + template + 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::value || + Kokkos::is_view::value ), + int>::type* = 0 ) { // Use the default execution space. build( execution_space{}, x, begin, end, neighborhood_radius, @@ -652,30 +695,34 @@ class VerletList \brief Given a list of particle positions and a neighborhood radius calculate the neighbor list. */ - template - void build( ExecutionSpace, PositionSlice x, const std::size_t begin, - const std::size_t end, - const typename PositionSlice::value_type 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 ) + template + 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::value || + Kokkos::is_view::value ), + int>::type* = 0 ) { Kokkos::Profiling::ScopedRegion region( "Cabana::VerletList::build" ); static_assert( is_accessible_from{}, "" ); assert( end >= begin ); - assert( end <= x.size() ); + assert( end <= size( x ) ); using device_type = Kokkos::Device; // Create a builder functor. - using builder_type = - Impl::VerletListBuilder; - builder_type builder( x, begin, end, neighborhood_radius, - cell_size_ratio, grid_min, grid_max, max_neigh ); + auto builder = + Impl::createVerletListBuilder( + x, begin, end, neighborhood_radius, cell_size_ratio, grid_min, + grid_max, max_neigh ); // For each particle in the range check each neighboring bin for // neighbor particles. Bins are at least the size of the neighborhood @@ -684,11 +731,11 @@ class VerletList // For CSR lists, we count, then fill neighbors. For 2D lists, we // count and fill at the same time, unless the array size is exceeded, // at which point only counting is continued to reallocate and refill. - typename builder_type::FillNeighborsPolicy fill_policy( + typename decltype( builder )::FillNeighborsPolicy fill_policy( builder.bin_data_1d.numBin(), Kokkos::AUTO, 4 ); if ( builder.count ) { - typename builder_type::CountNeighborsPolicy count_policy( + typename decltype( builder )::CountNeighborsPolicy count_policy( builder.bin_data_1d.numBin(), Kokkos::AUTO, 4 ); Kokkos::parallel_for( "Cabana::VerletList::count_neighbors", count_policy, builder ); diff --git a/core/unit_test/tstLinkedCellList.hpp b/core/unit_test/tstLinkedCellList.hpp index 2d3495475..72757f10b 100644 --- a/core/unit_test/tstLinkedCellList.hpp +++ b/core/unit_test/tstLinkedCellList.hpp @@ -706,6 +706,67 @@ void testLinkedCellReduce() test_data.end, test_data.test_radius ); } +//---------------------------------------------------------------------------// +void testLinkedListView() +{ + LCLTestData test_data; + auto grid_delta = test_data.grid_delta; + auto grid_min = test_data.grid_min; + auto grid_max = test_data.grid_max; + auto slice = Cabana::slice( test_data.aosoa ); + + // Copy manually into a View. + Kokkos::View view( "positions", slice.size(), 3 ); + copySliceToView( view, slice, 0, slice.size() ); + + // Bin the particles in the grid and permute only the position slice. + // First do this by only operating on a subset of the particles. + { + auto begin = test_data.begin; + auto end = test_data.end; + Cabana::LinkedCellList cell_list( + view, begin, end, grid_delta, grid_min, grid_max ); + Cabana::permute( cell_list, view ); + + // Copy manually back into the AoSoA to check values. + copyViewToSlice( slice, view, 0, slice.size() ); + + copyListToHost( test_data, cell_list ); + + checkBins( test_data, cell_list ); + checkLinkedCell( test_data, begin, end, false ); + } + // Now bin and permute all of the particles. + { + Cabana::LinkedCellList cell_list( view, grid_delta, + grid_min, grid_max ); + + // Copy manually into a View. + Kokkos::View view( "positions", slice.size(), + 3 ); + copySliceToView( view, slice, 0, slice.size() ); + + Cabana::permute( cell_list, view ); + + copyListToHost( test_data, cell_list ); + + checkBins( test_data, cell_list ); + checkLinkedCell( test_data, 0, test_data.num_p, false ); + + // Rebuild and make sure nothing changed. + cell_list.build( view ); + Cabana::permute( cell_list, view ); + + // Copy manually back into the AoSoA to check values. + copyViewToSlice( slice, view, 0, slice.size() ); + + copyListToHost( test_data, cell_list ); + + checkBins( test_data, cell_list ); + checkLinkedCell( test_data, 0, test_data.num_p, false ); + } +} + //---------------------------------------------------------------------------// // RUN TESTS //---------------------------------------------------------------------------// @@ -724,6 +785,9 @@ TEST( TEST_CATEGORY, linked_list_parallel_test ) { testLinkedCellParallel(); } TEST( TEST_CATEGORY, linked_list_reduce_test ) { testLinkedCellReduce(); } +//---------------------------------------------------------------------------// +TEST( TEST_CATEGORY, linked_list_view_test ) { testLinkedListView(); } + //---------------------------------------------------------------------------// } // end namespace Test diff --git a/core/unit_test/tstNeighborList.hpp b/core/unit_test/tstNeighborList.hpp index a89ff793e..0834e3be1 100644 --- a/core/unit_test/tstNeighborList.hpp +++ b/core/unit_test/tstNeighborList.hpp @@ -246,6 +246,36 @@ void testModifyNeighbors() } } +//---------------------------------------------------------------------------// +template +void testNeighborView() +{ + // Create the AoSoA and fill with random particle positions. + NeighborListTestData test_data; + auto slice = Cabana::slice<0>( test_data.aosoa ); + + // Copy manually into a View. + Kokkos::View view( "positions", slice.size(), 3 ); + auto view_copy = KOKKOS_LAMBDA( const int i ) + { + for ( std::size_t d = 0; d < 3; ++d ) + view( i, d ) = slice( i, d ); + }; + Kokkos::RangePolicy policy( 0, slice.size() ); + Kokkos::parallel_for( "view_copy", policy, view_copy ); + Kokkos::fence(); + + // Create the neighbor list with the View data. + using ListType = Cabana::VerletList; + ListType nlist( view, 0, view.extent( 0 ), test_data.test_radius, + test_data.cell_size_ratio, test_data.grid_min, + test_data.grid_max ); + + checkFullNeighborList( nlist, test_data.N2_list_copy, + test_data.num_particle ); +} + //---------------------------------------------------------------------------// template void testNeighborHistogram() @@ -385,6 +415,13 @@ TEST( TEST_CATEGORY, neighbor_histogram_test ) #endif testNeighborHistogram(); } +TEST( TEST_CATEGORY, view_test ) +{ +#ifndef KOKKOS_ENABLE_OPENMPTARGET // FIXME_OPENMPTARGET + testNeighborView(); +#endif + testNeighborView(); +} //---------------------------------------------------------------------------//