diff --git a/core/example/cuda_uvm_example.cu b/core/example/cuda_uvm_example.cu index 5ddb363b8a3195857ffbafd07dceaf64668433c5..67c356130724faae311b7bdaaff9daf28829600c 100644 --- a/core/example/cuda_uvm_example.cu +++ b/core/example/cuda_uvm_example.cu @@ -1,5 +1,6 @@ -#include "Cabana_AoSoA.hpp" -#include "Cabana_Cuda.hpp" +#include <Cabana_AoSoA.hpp> +#include <Cabana_MemberDataTypes.hpp> +#include <Cabana_Cuda.hpp> #include <cstdlib> #include <iostream> @@ -60,7 +61,7 @@ __global__ void initializeParticles( ParticleList particles ) { // Create a particle index. The Cuda block id is the struct id and the // thread id in the block is the array id in the struct. - ParticleList::Index idx( blockIdx.x, threadIdx.x ); + Cabana::Index idx( array_size, blockIdx.x, threadIdx.x ); // Only do the operation if we have a valid particle. if ( idx < particles.end() ) diff --git a/core/example/serial_example.cpp b/core/example/serial_example.cpp index 3fd01e56dbeca6b48ea90ea6e093f0e1d500fdd5..ac978ac9b26009d58f6475032d6bb623659fc68c 100644 --- a/core/example/serial_example.cpp +++ b/core/example/serial_example.cpp @@ -1,5 +1,6 @@ -#include "Cabana_AoSoA.hpp" -#include "Cabana_Serial.hpp" +#include <Cabana_AoSoA.hpp> +#include <Cabana_MemberDataTypes.hpp> +#include <Cabana_Serial.hpp> #include <cstdlib> #include <iostream> diff --git a/core/example/strided_example.cpp b/core/example/strided_example.cpp deleted file mode 100644 index edc9444e73218e83c769a0d2fd8d91776b678fe3..0000000000000000000000000000000000000000 --- a/core/example/strided_example.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "Cabana_AoSoA.hpp" -#include "Cabana_Serial.hpp" - -#include <cstdlib> -#include <iostream> - -//---------------------------------------------------------------------------// -// Define particle data. -//---------------------------------------------------------------------------// -// Inner array size (the size of the arrays in the structs-of-arrays). -// -// NOTE: It would be nice to have a dynamic option for this if possible. This -// would allow for a true SoA-only configuration where only enough memory for -// all the particles is allocated. Although AoSoA with very large inner array -// sizes may not perform any worse than SoA anyways so maybe this is not -// needed. -const std::size_t array_size = 10; - -// Spatial dimension. -const std::size_t space_dim = 3; - -// User field enumeration. These will be used to index into the data set. Must -// start at 0 and increment contiguously. -// -// NOTE: Users don't have to make this enum (or some other set of integral -// constants) but it is a nice way to provide meaning to the different data -// types and values assigned to the particles. -// -// NOTE: These enums are also ordered in the same way as the data in the -// template parameters below. -enum UserParticleFields -{ - PositionX = 0, - PositionY, - PositionZ, - Velocity, - Stress, - Status -}; - -// Designate the types that the particles will hold. -using ParticleDataTypes = - Cabana::MemberDataTypes<float, // (0) x-position type - float, // (1) y-position type - float, // (2) z-position type - double[space_dim], // (3) velocity type - double[space_dim][space_dim], // (4) stress type - int // (5) status type - >; - -// Set the type for the particle AoSoA. -using ParticleList = - Cabana::AoSoA<ParticleDataTypes,Cabana::Serial,array_size>; - -//---------------------------------------------------------------------------// -// Helper functions. -//---------------------------------------------------------------------------// -// Function to intitialize the particles. -void initializeParticles( ParticleList particles ) -{ - std::size_t num_s = particles.numSoA(); - for ( std::size_t s = 0; s < num_s; ++s ) - { - auto pos_x = particles.array<PositionX>( s ); - auto pos_y = particles.array<PositionY>( s ); - auto pos_z = particles.array<PositionZ>( s ); - auto velocity = particles.array<Velocity>( s ); - auto stress = particles.array<Stress>( s ); - auto status = particles.array<Status>( s ); - - std::size_t num_p = particles.arraySize( s ); - for ( int p = 0; p < num_p; ++p ) - { - pos_x[p] = 1.1; - pos_y[p] = 2.2; - pos_z[p] = 3.3; - - for ( int d = 0; d < space_dim; ++d ) - velocity[p][d] = 1.1 * d; - - for ( int j = 0; j < space_dim; ++j ) - for ( int i = 0; i < space_dim; ++i ) - stress[p][i][j] = ( i == j ) ? 1.0 : 0.0; - - status[p] = 1; - } - } -} - -// Function to print out the data for every particle. -void printParticles( const ParticleList particles ) -{ - for ( auto idx = particles.begin(); - idx != particles.end(); - ++idx ) - { - std::cout << std::endl; - - std::cout << "Struct id: " << idx.s() << std::endl; - std::cout << "Struct offset: " << idx.i() << std::endl; - std::cout << "Position: " - << particles.get<PositionX>( idx ) << " " - << particles.get<PositionY>( idx ) << " " - << particles.get<PositionZ>( idx ) << std::endl; - - std::cout << "Velocity "; - for ( int d = 0; d < space_dim; ++d ) - std::cout << particles.get<Velocity>( idx, d ) << " "; - std::cout << std::endl; - - std::cout << "Stress "; - for ( int j = 0; j < space_dim; ++j ) - { - std::cout << "{ "; - for ( int i = 0; i < space_dim; ++i ) - std::cout << particles.get<Stress>( idx, i, j ) << " " ; - std::cout << "}"; - } - std::cout << std::endl; - - std::cout << "Status " << particles.get<Status>(idx) << std::endl; - } -} - -//---------------------------------------------------------------------------// -// Main. -//---------------------------------------------------------------------------// -int main() -{ - // Declare a number of particles. - int num_particle = 45; - - // Create the particle list. - ParticleList particles( num_particle ); - - // Initialize particles. - initializeParticles( particles ); - - // Print particles. - printParticles( particles ); - - return 0; -} - -//---------------------------------------------------------------------------// diff --git a/core/src/Cabana_AoSoA.hpp b/core/src/Cabana_AoSoA.hpp index bf98fc4d92465bbfd3ec47a308c90aa96523c7eb..62266f5d85f2118bce3660153112e331e5f5a9ae 100644 --- a/core/src/Cabana_AoSoA.hpp +++ b/core/src/Cabana_AoSoA.hpp @@ -46,12 +46,6 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> // AoSoA type. using aosoa_type = AoSoA<MemberDataTypes<Types...>,Device,ArraySize>; - // Member data types. - using member_types = MemberDataTypes<Types...>; - - // Number of member types. - static constexpr std::size_t number_of_members = member_types::size; - // Device type. using device_type = Device; @@ -64,6 +58,15 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> // SoA type. using soa_type = SoA<array_size,Types...>; + // Member data types. + using member_types = MemberDataTypes<Types...>; + + // Number of member types. + static constexpr std::size_t number_of_members = member_types::size; + + // The maximum rank supported for member types. + static constexpr std::size_t max_supported_rank = 4; + // Struct member array return type at a given index I. template<std::size_t I> using struct_member_array_type = @@ -112,8 +115,10 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> , _capacity( 0 ) , _num_soa( 0 ) , _managed_data( nullptr ) - , _raw_data( nullptr ) - {} + { + storeRanksAndExtents( + std::integral_constant<std::size_t,number_of_members-1>() ); + } // Construct a container with n elements. AoSoA( const std::size_t n ) @@ -121,9 +126,10 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> , _capacity( 0 ) , _num_soa( 0 ) , _managed_data( nullptr ) - , _raw_data( nullptr ) { resize( _size ); + storeRanksAndExtents( + std::integral_constant<std::size_t,number_of_members-1>() ); } // Returns the number of elements in the container. @@ -192,16 +198,18 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> if ( 0 < n % array_size ) ++num_soa_alloc; _capacity = num_soa_alloc * array_size; - soa_type* rp; - memory_policy::allocate( rp, num_soa_alloc ); + soa_type* data_block; + memory_policy::allocate( data_block, num_soa_alloc ); std::shared_ptr<soa_type> sp( - rp, memory_policy::template deallocate<soa_type> ); + data_block, memory_policy::template deallocate<soa_type> ); - if ( _raw_data != nullptr ) - memory_policy::copy( rp, _raw_data, _num_soa ); + if ( _managed_data != nullptr ) + memory_policy::copy( data_block, _managed_data.get(), _num_soa ); std::swap( _managed_data, sp ); - std::swap( _raw_data, rp ); + + storePointersAndStrides( + std::integral_constant<std::size_t,number_of_members-1>() ); } // Get the number of structs-of-arrays in the array. @@ -220,19 +228,17 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> // Member data type properties. // Get the rank of the data for a given member at index I. - template<std::size_t I> CABANA_INLINE_FUNCTION - constexpr std::size_t rank() const + std::size_t rank( const std::size_t I ) const { - return std::rank<struct_member_data_type<I> >::value; + return _ranks[I]; } // Get the extent of a given member data dimension. - template<std::size_t I, std::size_t DIM> CABANA_INLINE_FUNCTION - constexpr std::size_t extent() const + std::size_t extent( const std::size_t I, const std::size_t D ) const { - return std::extent<struct_member_data_type<I>,DIM>::value; + return _extents[I][D]; } // ----------------------------- @@ -374,51 +380,148 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> // ------------------------------- // Raw data access. - // Get the stride between SoA data for a given member at index I. - template<std::size_t I> + // Get the stride between SoA data for a given member at index I. Note + // that this strides are computed in the context of the *value_type* for + // each member. CABANA_INLINE_FUNCTION - constexpr std::size_t stride() const + std::size_t stride( const std::size_t I ) const { - static_assert( 0 == - sizeof(soa_type) % sizeof(struct_member_value_type<I>), - "Stride cannont be calculated for misaligned memory!" ); - return sizeof(soa_type) / sizeof(struct_member_value_type<I>); + return _strides[I]; } - // Get a pointer to the data for a given member at index I. - template<std::size_t I> + // Get an un-typed raw pointer to the data for a given member at index + // I. Users will need to cast this pointer to the appropriate type for the + // stride associated with this member to mean anything. CABANA_INLINE_FUNCTION - struct_member_pointer_type<I> pointer() + void* data( const std::size_t I ) { - return static_cast<struct_member_pointer_type<I> >( array<I>(0) ); + return _pointers[I]; } - template<std::size_t I> CABANA_INLINE_FUNCTION - struct_member_const_pointer_type<I> pointer() const + const void* data( const std::size_t I ) const { - return static_cast<struct_member_pointer_type<I> >( array<I>(0) ); + return _pointers[I]; } private: - // ------------------------------- - // Direct array data access within a struct + // Get a typed pointer to the data for a given member at index I. + template<std::size_t I> + CABANA_INLINE_FUNCTION + struct_member_pointer_type<I> typedPointer() + { + return static_cast<struct_member_pointer_type<I> >( _pointers[I] ); + } - // Access the data array at a given struct member index. template<std::size_t I> CABANA_INLINE_FUNCTION - struct_member_array_type<I> array( const std::size_t s ) + struct_member_const_pointer_type<I> typedPointer() const { + return static_cast<struct_member_pointer_type<I> >( _pointers[I] ); + } - return getStructMember<I>( _raw_data[s] ); + // Get the array at the given struct index. + template<std::size_t I> + CABANA_INLINE_FUNCTION + struct_member_array_type<I> array( const std::size_t s ) + { + return reinterpret_cast<struct_member_array_type<I> >( + typedPointer<I>() + s * _strides[I] ); } template<std::size_t I> CABANA_INLINE_FUNCTION struct_member_const_array_type<I> array( const std::size_t s ) const { - return getStructMember<I>( _raw_data[s] ); + return reinterpret_cast<struct_member_array_type<I> >( + typedPointer<I>() + s * _strides[I] ); + } + + // Store the pointers and strides for each member element. + template<std::size_t N> + void assignPointersAndStrides() + { + static_assert( 0 <= N && N < number_of_members, + "Static loop out of bounds!" ); + soa_type* data_block = _managed_data.get(); + _pointers[N] = + static_cast<void*>( getStructMember<N>(data_block[0]) ); + static_assert( 0 == + sizeof(soa_type) % sizeof(struct_member_value_type<N>), + "Stride cannont be calculated for misaligned memory!" ); + _strides[N] = sizeof(soa_type) / sizeof(struct_member_value_type<N>); + } + + // Static loop through each member element to extract pointers and strides. + template<std::size_t N> + void storePointersAndStrides( std::integral_constant<std::size_t,N> ) + { + assignPointersAndStrides<N>(); + storePointersAndStrides( std::integral_constant<std::size_t,N-1>() ); + } + + void storePointersAndStrides( std::integral_constant<std::size_t,0> ) + { + assignPointersAndStrides<0>(); + } + + // Store the extents of each of the member types. + template<std::size_t I, std::size_t N> + void assignExtents() + { + static_assert( 0 <= N && N < max_supported_rank, + "Static loop out of bounds!" ); + _extents[I][N] = ( N < std::rank<struct_member_data_type<I> >::value ) + ? std::extent<struct_member_data_type<I>,N>::value + : 0; + } + + // Static loop over extents for each member element. + template<std::size_t I, std::size_t N> + void storeExtents( std::integral_constant<std::size_t,I>, + std::integral_constant<std::size_t,N> ) + { + assignExtents<I,N>(); + storeExtents( std::integral_constant<std::size_t,I>(), + std::integral_constant<std::size_t,N-1>() ); + } + + template<std::size_t I> + void storeExtents( std::integral_constant<std::size_t,I>, + std::integral_constant<std::size_t,0> ) + { + assignExtents<I,0>(); + } + + // Store the rank for each member element type. + template<std::size_t N> + void assignRanks() + { + static_assert( std::rank<struct_member_data_type<N> >::value <= + max_supported_rank, + "Member type rank larger than max supported rank" ); + static_assert( 0 <= N && N < number_of_members, "Static loop out of bounds!" ); + _ranks[N] = std::rank<struct_member_data_type<N> >::value; + } + + // Static loop over ranks and extents for each element. + template<std::size_t N> + void storeRanksAndExtents( std::integral_constant<std::size_t,N> ) + { + assignRanks<N>(); + storeExtents( + std::integral_constant<std::size_t,N>(), + std::integral_constant<std::size_t,max_supported_rank-1>() ); + storeRanksAndExtents( std::integral_constant<std::size_t,N-1>() ); + } + + void storeRanksAndExtents( std::integral_constant<std::size_t,0> ) + { + storeExtents( + std::integral_constant<std::size_t,0>(), + std::integral_constant<std::size_t,max_supported_rank-1>() ); + assignRanks<0>(); } private: @@ -432,18 +535,24 @@ class AoSoA<MemberDataTypes<Types...>,Device,ArraySize> // Number of structs-of-arrays in the array. std::size_t _num_soa; - // Structs-of-Arrays managed data. This shared pointer manages the memory - // pointed to by _raw_data such that the copy constructor and assignment - // operator for this class perform a shallow and reference counted copy of - // the data. + // Structs-of-Arrays managed data. This shared pointer manages the block + // of memory owned by this class such that the copy constructor and + // assignment operator for this class perform a shallow and reference + // counted copy of the data. std::shared_ptr<soa_type> _managed_data; - // Structs-of-Arrays raw data. This data will be allocated per the - // MemoryPolicy of the given device type on which the class is - // templated. This pointer is managed by _managed_data and will be - // deallocated per the MemoryPolicy when the last copy of this class - // instance is destroyed. - soa_type* _raw_data; + // Pointers to the first element of each member. + void* _pointers[number_of_members]; + + // Strides for each member. Note that these strides are computed in the + // context of the *value_type* of each member. + std::size_t _strides[number_of_members]; + + // The ranks of each of the data member types. + std::size_t _ranks[number_of_members]; + + // The extents of each of the data member type dimensions. + std::size_t _extents[number_of_members][max_supported_rank]; }; //---------------------------------------------------------------------------// diff --git a/core/src/Cabana_MemberSlice.hpp b/core/src/Cabana_MemberSlice.hpp index 566e765bd94f9b45ee2f11b55b3c50fc487ad800..22667cf0a50414832b6d5eed21c991da9af017ac 100644 --- a/core/src/Cabana_MemberSlice.hpp +++ b/core/src/Cabana_MemberSlice.hpp @@ -117,14 +117,13 @@ class MemberSlice // Get the rank of the data for this member. CABANA_INLINE_FUNCTION - constexpr std::size_t rank() const - { return _aosoa.template rank<I>(); } + std::size_t rank() const + { return _aosoa.rank(I); } // Get the extent of a given member data dimension. - template<std::size_t DIM> CABANA_INLINE_FUNCTION - constexpr std::size_t extent() const - { return _aosoa.template extent<I,DIM>(); } + std::size_t extent( const std::size_t D ) const + { return _aosoa.extent(I,D); } // ----------------------------- // Array range @@ -293,23 +292,6 @@ class MemberSlice return _aosoa.template get<J>(idx,d0,d1,d2,d3); } - // ------------------------------- - // Raw data access. - - // Get the stride between SoA data for a given member at index I. - CABANA_INLINE_FUNCTION - constexpr std::size_t stride() const - { return _aosoa.template stride<I>(); } - - // Get a pointer to the data for a given member at index I. - CABANA_INLINE_FUNCTION - pointer_type pointer() - { return _aosoa.template pointer<I>(); } - - CABANA_INLINE_FUNCTION - const_pointer_type pointer() const - { return _aosoa.template pointer<I>(); } - private: // The array-of-structs-of-arrays this slice wraps. We hold this by value diff --git a/core/unit_test/tstAoSoA.cpp b/core/unit_test/tstAoSoA.cpp index 46b2c2be5f116c6970416a359100fa93072d1b2e..866809637308d01a9b274b7bda8cdd75364de993 100644 --- a/core/unit_test/tstAoSoA.cpp +++ b/core/unit_test/tstAoSoA.cpp @@ -73,48 +73,77 @@ BOOST_AUTO_TEST_CASE( aosoa_serial_api_test ) BOOST_TEST( Cabana::is_aosoa<AoSoA_t>::value ); // Create an AoSoA. - std::size_t num_data = 35; - AoSoA_t aosoa( num_data ); + AoSoA_t aosoa; // Check sizes. - BOOST_TEST( aosoa.size() == std::size_t(35) ); - BOOST_TEST( aosoa.capacity() == std::size_t(40) ); - BOOST_TEST( aosoa.numSoA() == std::size_t(4) ); - - BOOST_TEST( aosoa.arraySize(0) == std::size_t(10) ); - BOOST_TEST( aosoa.arraySize(1) == std::size_t(10) ); - BOOST_TEST( aosoa.arraySize(2) == std::size_t(10) ); - BOOST_TEST( aosoa.arraySize(3) == std::size_t(5) ); + BOOST_TEST( aosoa.size() == std::size_t(0) ); + BOOST_TEST( aosoa.capacity() == std::size_t(0) ); + BOOST_TEST( aosoa.numSoA() == std::size_t(0) ); - BOOST_TEST( aosoa.rank<0>() == std::size_t(3) ); - std::size_t e00 = aosoa.extent<0,0>(); + // Check member type properties. + BOOST_TEST( aosoa.rank(0) == std::size_t(3) ); + std::size_t e00 = aosoa.extent(0,0); BOOST_TEST( e00 == dim_1 ); - std::size_t e01 = aosoa.extent<0,1>(); + std::size_t e01 = aosoa.extent(0,1); BOOST_TEST( e01 == dim_2 ); - std::size_t e02 = aosoa.extent<0,2>(); + std::size_t e02 = aosoa.extent(0,2); BOOST_TEST( e02 == dim_3 ); - - BOOST_TEST( aosoa.rank<1>() == std::size_t(0) ); - - BOOST_TEST( aosoa.rank<2>() == std::size_t(4) ); - std::size_t e20 = aosoa.extent<2,0>(); + std::size_t e03 = aosoa.extent(0,3); + BOOST_TEST( e03 == std::size_t(0) ); + + BOOST_TEST( aosoa.rank(1) == std::size_t(0) ); + std::size_t e10 = aosoa.extent(1,0); + BOOST_TEST( e10 == std::size_t(0) ); + std::size_t e11 = aosoa.extent(1,1); + BOOST_TEST( e11 == std::size_t(0) ); + std::size_t e12 = aosoa.extent(1,2); + BOOST_TEST( e12 == std::size_t(0) ); + std::size_t e13 = aosoa.extent(1,3); + BOOST_TEST( e13 == std::size_t(0) ); + + BOOST_TEST( aosoa.rank(2) == std::size_t(4) ); + std::size_t e20 = aosoa.extent(2,0); BOOST_TEST( e20 == dim_1 ); - std::size_t e21 = aosoa.extent<2,1>(); + std::size_t e21 = aosoa.extent(2,1); BOOST_TEST( e21 == dim_2 ); - std::size_t e22 = aosoa.extent<2,2>(); + std::size_t e22 = aosoa.extent(2,2); BOOST_TEST( e22 == dim_3 ); - std::size_t e23 = aosoa.extent<2,3>(); + std::size_t e23 = aosoa.extent(2,3); BOOST_TEST( e23 == dim_4 ); - BOOST_TEST( aosoa.rank<3>() == std::size_t(1) ); - std::size_t e30 = aosoa.extent<3,0>(); + BOOST_TEST( aosoa.rank(3) == std::size_t(1) ); + std::size_t e30 = aosoa.extent(3,0); BOOST_TEST( e30 == dim_1 ); - - BOOST_TEST( aosoa.rank<4>() == std::size_t(2) ); - std::size_t e40 = aosoa.extent<4,0>(); + std::size_t e31 = aosoa.extent(3,1); + BOOST_TEST( e31 == std::size_t(0) ); + std::size_t e32 = aosoa.extent(3,2); + BOOST_TEST( e32 == std::size_t(0) ); + std::size_t e33 = aosoa.extent(3,3); + BOOST_TEST( e33 == std::size_t(0) ); + + BOOST_TEST( aosoa.rank(4) == std::size_t(2) ); + std::size_t e40 = aosoa.extent(4,0); BOOST_TEST( e40 == dim_1 ); - std::size_t e41 = aosoa.extent<4,1>(); + std::size_t e41 = aosoa.extent(4,1); BOOST_TEST( e41 == dim_2 ); + std::size_t e42 = aosoa.extent(4,2); + BOOST_TEST( e42 == std::size_t(0) ); + std::size_t e43 = aosoa.extent(4,3); + BOOST_TEST( e43 == std::size_t(0) ); + + // Resize + std::size_t num_data = 35; + aosoa.resize( num_data ); + + // Check sizes for the new allocation/size. + BOOST_TEST( aosoa.size() == std::size_t(35) ); + BOOST_TEST( aosoa.capacity() == std::size_t(40) ); + BOOST_TEST( aosoa.numSoA() == std::size_t(4) ); + + BOOST_TEST( aosoa.arraySize(0) == std::size_t(10) ); + BOOST_TEST( aosoa.arraySize(1) == std::size_t(10) ); + BOOST_TEST( aosoa.arraySize(2) == std::size_t(10) ); + BOOST_TEST( aosoa.arraySize(3) == std::size_t(5) ); // Initialize data with the rank accessors. float fval = 3.4; @@ -193,16 +222,20 @@ BOOST_AUTO_TEST_CASE( aosoa_serial_api_test ) } //---------------------------------------------------------------------------// -BOOST_AUTO_TEST_CASE( aosoa_serial_pointer_stride_test ) +BOOST_AUTO_TEST_CASE( aosoa_raw_data_test ) { // Inner array size. const std::size_t array_size = 103; + // Multi dimensional member sizes. + const std::size_t dim_1 = 3; + const std::size_t dim_2 = 5; + // Declare data types. Note that this test only uses rank-0 data. using DataTypes = Cabana::MemberDataTypes<float, int, - double, + double[dim_1][dim_2], int, double >; @@ -211,40 +244,28 @@ BOOST_AUTO_TEST_CASE( aosoa_serial_pointer_stride_test ) using AoSoA_t = Cabana::AoSoA<DataTypes,Cabana::Serial,array_size>; // Create an AoSoA using the default constructor. - AoSoA_t aosoa; - - // Check sizes. - BOOST_TEST( aosoa.size() == std::size_t(0) ); - BOOST_TEST( aosoa.capacity() == std::size_t(0) ); - BOOST_TEST( aosoa.numSoA() == std::size_t(0) ); - - // Resize. std::size_t num_data = 350; - aosoa.resize( num_data ); - - // Check sizes. - BOOST_TEST( aosoa.size() == std::size_t(350) ); - BOOST_TEST( aosoa.capacity() == std::size_t(412) ); - BOOST_TEST( aosoa.numSoA() == std::size_t(4) ); - - BOOST_TEST( aosoa.arraySize(0) == std::size_t(103) ); - BOOST_TEST( aosoa.arraySize(1) == std::size_t(103) ); - BOOST_TEST( aosoa.arraySize(2) == std::size_t(103) ); - BOOST_TEST( aosoa.arraySize(3) == std::size_t(41) ); + AoSoA_t aosoa( num_data ); - // Get pointers to the data. - float* p0 = aosoa.pointer<0>(); - int* p1 = aosoa.pointer<1>(); - double* p2 = aosoa.pointer<2>(); - int* p3 = aosoa.pointer<3>(); - double* p4 = aosoa.pointer<4>(); + // Get raw pointers to the data as one would in a C interface (no templates). + float* p0 = (float*) aosoa.data(0); + int* p1 = (int*) aosoa.data(1); + double* p2 = (double*) aosoa.data(2); + int* p3 = (int*) aosoa.data(3); + double* p4 = (double*) aosoa.data(4); // Get the strides between the member arrays. - std::size_t st0 = aosoa.stride<0>(); - std::size_t st1 = aosoa.stride<1>(); - std::size_t st2 = aosoa.stride<2>(); - std::size_t st3 = aosoa.stride<3>(); - std::size_t st4 = aosoa.stride<4>(); + std::size_t st0 = aosoa.stride(0); + std::size_t st1 = aosoa.stride(1); + std::size_t st2 = aosoa.stride(2); + std::size_t st3 = aosoa.stride(3); + std::size_t st4 = aosoa.stride(4); + + // Member 2 is multidimensional so get its extents. + std::size_t m2e0 = aosoa.extent(2,0); + std::size_t m2e1 = aosoa.extent(2,1); + BOOST_TEST( m2e0 == dim_1 ); + BOOST_TEST( m2e1 == dim_2 ); // Initialize the data with raw pointer/stride access. Start by looping // over the structs. Each struct has a group of contiguous arrays of size @@ -258,9 +279,15 @@ BOOST_AUTO_TEST_CASE( aosoa_serial_pointer_stride_test ) { p0[ s * st0 + i ] = (s + i) * 1.0; p1[ s * st1 + i ] = (s + i) * 2; - p2[ s * st2 + i ] = (s + i) * 3.0; p3[ s * st3 + i ] = (s + i) * 4; p4[ s * st4 + i ] = (s + i) * 5.0; + + // Member 2 has some extra dimensions so add those to the + // indexing. + for ( std::size_t j = 0; j < m2e0; ++j ) + for ( std::size_t k = 0; k < m2e1; ++k ) + p2[ s * st2 + i * m2e0 * m2e1 + j * m2e1 + k ] = + (s + i + j + k) * 3.0; } } @@ -271,8 +298,12 @@ BOOST_AUTO_TEST_CASE( aosoa_serial_pointer_stride_test ) std::size_t i = idx.i(); BOOST_TEST( aosoa.get<0>(idx) == (s+i)*1.0 ); BOOST_TEST( aosoa.get<1>(idx) == int((s+i)*2) ); - BOOST_TEST( aosoa.get<2>(idx) == (s+i)*3.0 ); BOOST_TEST( aosoa.get<3>(idx) == int((s+i)*4) ); BOOST_TEST( aosoa.get<4>(idx) == (s+i)*5.0 ); + + // Member 2 has some extra dimensions so check those too. + for ( std::size_t j = 0; j < dim_1; ++j ) + for ( std::size_t k = 0; k < dim_2; ++k ) + BOOST_TEST( aosoa.get<2>(idx,j,k) == (s+i+j+k)*3.0 ); } } diff --git a/core/unit_test/tstMemberSlice.cpp b/core/unit_test/tstMemberSlice.cpp index 89dfe04416486a773a69c3ec4e5a3ef3e0d4fa64..c87a4f8aa4f85aa42c0c64b572505b052dd4dc22 100644 --- a/core/unit_test/tstMemberSlice.cpp +++ b/core/unit_test/tstMemberSlice.cpp @@ -100,6 +100,56 @@ BOOST_AUTO_TEST_CASE( slice_serial_api_test ) BOOST_TEST( slice_0.arraySize(2) == std::size_t(10) ); BOOST_TEST( slice_0.arraySize(3) == std::size_t(5) ); + BOOST_TEST( slice_0.rank() == std::size_t(3) ); + std::size_t e00 = slice_0.extent(0); + BOOST_TEST( e00 == dim_1 ); + std::size_t e01 = slice_0.extent(1); + BOOST_TEST( e01 == dim_2 ); + std::size_t e02 = slice_0.extent(2); + BOOST_TEST( e02 == dim_3 ); + std::size_t e03 = slice_0.extent(3); + BOOST_TEST( e03 == std::size_t(0) ); + + BOOST_TEST( slice_1.rank() == std::size_t(0) ); + std::size_t e10 = slice_1.extent(0); + BOOST_TEST( e10 == std::size_t(0) ); + std::size_t e11 = slice_1.extent(1); + BOOST_TEST( e11 == std::size_t(0) ); + std::size_t e12 = slice_1.extent(2); + BOOST_TEST( e12 == std::size_t(0) ); + std::size_t e13 = slice_1.extent(3); + BOOST_TEST( e13 == std::size_t(0) ); + + BOOST_TEST( slice_2.rank() == std::size_t(4) ); + std::size_t e20 = slice_2.extent(0); + BOOST_TEST( e20 == dim_1 ); + std::size_t e21 = slice_2.extent(1); + BOOST_TEST( e21 == dim_2 ); + std::size_t e22 = slice_2.extent(2); + BOOST_TEST( e22 == dim_3 ); + std::size_t e23 = slice_2.extent(3); + BOOST_TEST( e23 == dim_4 ); + + BOOST_TEST( slice_3.rank() == std::size_t(1) ); + std::size_t e30 = slice_3.extent(0); + BOOST_TEST( e30 == dim_1 ); + std::size_t e31 = slice_3.extent(1); + BOOST_TEST( e31 == std::size_t(0) ); + std::size_t e32 = slice_3.extent(2); + BOOST_TEST( e32 == std::size_t(0) ); + std::size_t e33 = slice_3.extent(3); + BOOST_TEST( e33 == std::size_t(0) ); + + BOOST_TEST( slice_4.rank() == std::size_t(2) ); + std::size_t e40 = slice_4.extent(0); + BOOST_TEST( e40 == dim_1 ); + std::size_t e41 = slice_4.extent(1); + BOOST_TEST( e41 == dim_2 ); + std::size_t e42 = slice_4.extent(2); + BOOST_TEST( e42 == std::size_t(0) ); + std::size_t e43 = slice_4.extent(3); + BOOST_TEST( e43 == std::size_t(0) ); + // Initialize data with the rank accessors. float fval = 3.4; double dval = 1.23; @@ -135,77 +185,3 @@ BOOST_AUTO_TEST_CASE( slice_serial_api_test ) // Check data members for proper initialization. checkDataMembers( aosoa, fval, dval, ival, dim_1, dim_2, dim_3, dim_4 ); } - -//---------------------------------------------------------------------------// -BOOST_AUTO_TEST_CASE( slice_serial_pointer_stride_test ) -{ - // Inner array size. - const std::size_t array_size = 103; - - // Declare data types. Note that this test only uses rank-0 data. - using DataTypes = - Cabana::MemberDataTypes<float, - int, - double, - int, - double - >; - - // Declare the AoSoA type. - using AoSoA_t = Cabana::AoSoA<DataTypes,Cabana::Serial,array_size>; - - // Create an AoSoA. - std::size_t num_data = 350; - AoSoA_t aosoa( num_data ); - - // Create some slices. - auto slice_0 = Cabana::slice<0>( aosoa ); - auto slice_1 = Cabana::slice<1>( aosoa ); - auto slice_2 = Cabana::slice<2>( aosoa ); - auto slice_3 = Cabana::slice<3>( aosoa ); - auto slice_4 = Cabana::slice<4>( aosoa ); - - // Get pointers to the data. - float* p0 = slice_0.pointer(); - int* p1 = slice_1.pointer(); - double* p2 = slice_2.pointer(); - int* p3 = slice_3.pointer(); - double* p4 = slice_4.pointer(); - - // Get the strides between the member arrays. - std::size_t st0 = slice_0.stride(); - std::size_t st1 = slice_1.stride(); - std::size_t st2 = slice_2.stride(); - std::size_t st3 = slice_3.stride(); - std::size_t st4 = slice_4.stride(); - - // Initialize the data with raw pointer/stride access. Start by looping - // over the structs. Each struct has a group of contiguous arrays of size - // array_size for each member. - std::size_t num_soa = slice_0.numSoA(); - for ( std::size_t s = 0; s < num_soa; ++s ) - { - // Loop over the array in each struct and set the values. - std::size_t local_array_size = slice_0.arraySize( s ); - for ( std::size_t i = 0; i < local_array_size; ++i ) - { - p0[ s * st0 + i ] = (s + i) * 1.0; - p1[ s * st1 + i ] = (s + i) * 2; - p2[ s * st2 + i ] = (s + i) * 3.0; - p3[ s * st3 + i ] = (s + i) * 4; - p4[ s * st4 + i ] = (s + i) * 5.0; - } - } - - // Check the results. - for ( auto idx = aosoa.begin(); idx < aosoa.end(); ++idx ) - { - std::size_t s = idx.s(); - std::size_t i = idx.i(); - BOOST_TEST( aosoa.get<0>(idx) == (s+i)*1.0 ); - BOOST_TEST( aosoa.get<1>(idx) == int((s+i)*2) ); - BOOST_TEST( aosoa.get<2>(idx) == (s+i)*3.0 ); - BOOST_TEST( aosoa.get<3>(idx) == int((s+i)*4) ); - BOOST_TEST( aosoa.get<4>(idx) == (s+i)*5.0 ); - } -}