Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_DeepCopy.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_DEEPCOPY_HPP
17#define CABANA_DEEPCOPY_HPP
18
19#include <Cabana_AoSoA.hpp>
21#include <Cabana_Slice.hpp>
22#include <impl/Cabana_TypeTraits.hpp>
23
24#include <Kokkos_Core.hpp>
25
26#include <exception>
27#include <type_traits>
28
29namespace Cabana
30{
31//---------------------------------------------------------------------------//
36template <class Space, class SrcAoSoA>
39 const Space&, const SrcAoSoA& src,
40 typename std::enable_if<
41 ( !std::is_same<typename SrcAoSoA::memory_space,
42 typename Space::memory_space>::value )>::type* = 0 )
43{
44 static_assert( is_aosoa<SrcAoSoA>::value,
45 "create_mirror() requires an AoSoA" );
46 return AoSoA<typename SrcAoSoA::member_types, Space,
47 SrcAoSoA::vector_length>(
48 std::string( src.label() ).append( "_mirror" ), src.size() );
49}
50
51//---------------------------------------------------------------------------//
61template <class Space, class SrcAoSoA>
62inline SrcAoSoA create_mirror_view(
63 const Space&, const SrcAoSoA& src,
64 typename std::enable_if<
65 ( std::is_same<typename SrcAoSoA::memory_space,
66 typename Space::memory_space>::value )>::type* = 0 )
67{
68 static_assert( is_aosoa<SrcAoSoA>::value,
69 "create_mirror_view() requires an AoSoA" );
70 return src;
71}
72
73//---------------------------------------------------------------------------//
83template <class Space, class SrcAoSoA>
84inline AoSoA<typename SrcAoSoA::member_types, Space, SrcAoSoA::vector_length>
86 const Space& space, const SrcAoSoA& src,
87 typename std::enable_if<
88 ( !std::is_same<typename SrcAoSoA::memory_space,
89 typename Space::memory_space>::value )>::type* = 0 )
90{
91 static_assert( is_aosoa<SrcAoSoA>::value,
92 "create_mirror_view() requires an AoSoA" );
93 return create_mirror( space, src );
94}
95
96//---------------------------------------------------------------------------//
107template <class Space, class SrcAoSoA>
109 const Space&, const SrcAoSoA& src,
110 typename std::enable_if<
111 ( std::is_same<typename SrcAoSoA::memory_space,
112 typename Space::memory_space>::value &&
113 is_aosoa<SrcAoSoA>::value )>::type* = 0 )
114{
115 return src;
116}
117
118//---------------------------------------------------------------------------//
129template <class Space, class SrcAoSoA>
130inline AoSoA<typename SrcAoSoA::member_types, Space, SrcAoSoA::vector_length>
132 const Space& space, const SrcAoSoA& src,
133 typename std::enable_if<
134 ( !std::is_same<typename SrcAoSoA::memory_space,
135 typename Space::memory_space>::value &&
136 is_aosoa<SrcAoSoA>::value )>::type* = 0 )
137{
138 auto dst = create_mirror( space, src );
139
140 Kokkos::deep_copy(
141 typename decltype( dst )::soa_view( dst.data(), dst.numSoA() ),
142 typename SrcAoSoA::soa_view( src.data(), src.numSoA() ) );
143
144 return dst;
145}
146
147//---------------------------------------------------------------------------//
156template <class DstAoSoA, class SrcAoSoA>
157inline void
158deep_copy( DstAoSoA& dst, const SrcAoSoA& src,
159 typename std::enable_if<( is_aosoa<DstAoSoA>::value &&
160 is_aosoa<SrcAoSoA>::value )>::type* = 0 )
161{
162 using dst_type = DstAoSoA;
163 using src_type = SrcAoSoA;
164 using dst_memory_space = typename dst_type::memory_space;
165 using src_memory_space = typename src_type::memory_space;
166 using dst_soa_type = typename dst_type::soa_type;
167 using src_soa_type = typename src_type::soa_type;
168
169 // Check that the data types are the same.
170 static_assert(
171 std::is_same<typename dst_type::member_types,
172 typename src_type::member_types>::value,
173 "Attempted to deep copy AoSoA objects of different member types" );
174
175 // Check for the same number of values.
176 if ( dst.size() != src.size() )
177 {
178 throw std::runtime_error(
179 "Attempted to deep copy AoSoA objects of different sizes" );
180 }
181
182 // Get the pointers to the beginning of the data blocks.
183 void* dst_data = dst.data();
184 const void* src_data = src.data();
185
186 // Return if both pointers are null.
187 if ( dst_data == nullptr && src_data == nullptr )
188 {
189 return;
190 }
191
192 // Get the number of SoA's in each object.
193 auto dst_num_soa = dst.numSoA();
194 auto src_num_soa = src.numSoA();
195
196 // Return if the AoSoA memory occupies the same space.
197 if ( ( dst_data == src_data ) && ( dst_num_soa * sizeof( dst_soa_type ) ==
198 src_num_soa * sizeof( src_soa_type ) ) )
199 {
200 return;
201 }
202
203 // If the inner array size is the same and both AoSoAs have the same number
204 // of values then we can do a byte-wise copy directly.
205 if ( std::is_same<dst_soa_type, src_soa_type>::value )
206 {
207 Kokkos::deep_copy( Kokkos::View<char*, dst_memory_space>(
208 reinterpret_cast<char*>( dst.data() ),
209 dst.numSoA() * sizeof( dst_soa_type ) ),
210 Kokkos::View<char*, src_memory_space>(
211 reinterpret_cast<char*>( src.data() ),
212 src.numSoA() * sizeof( src_soa_type ) ) );
213 }
214
215 // Otherwise copy the data element-by-element because the data layout is
216 // different.
217 else
218 {
219 // Create an AoSoA in the destination space with the same data layout
220 // as the source.
221 auto src_copy_on_dst = create_mirror_view_and_copy(
222 typename dst_type::memory_space(), src );
223
224 // Copy via tuples.
225 auto copy_func = KOKKOS_LAMBDA( const std::size_t i )
226 {
227 dst.setTuple( i, src_copy_on_dst.getTuple( i ) );
228 };
229 Kokkos::RangePolicy<typename dst_type::execution_space> exec_policy(
230 0, dst.size() );
231 Kokkos::parallel_for( "Cabana::deep_copy", exec_policy, copy_func );
232 Kokkos::fence();
233 }
234}
235
236//---------------------------------------------------------------------------//
242template <class DstMemorySpace, class SrcMemorySpace, int DstVectorLength,
243 int SrcVectorLength, class... FieldTags>
244inline void deep_copy(
247{
248 // Copy particle data to new memory space.
249 auto aosoa_src = src.aosoa();
250 auto& aosoa_dst = dst.aosoa();
251
252 // Set the new data.
253 Cabana::deep_copy( aosoa_dst, aosoa_src );
254}
255
256//---------------------------------------------------------------------------//
263template <class AoSoA_t>
264inline void deep_copy( AoSoA_t& aosoa,
265 const typename AoSoA_t::tuple_type& tuple )
266{
267 static_assert( is_aosoa<AoSoA_t>::value,
268 "Only AoSoAs can be assigned tuples" );
269 auto assign_func = KOKKOS_LAMBDA( const std::size_t i )
270 {
271 aosoa.setTuple( i, tuple );
272 };
273 Kokkos::RangePolicy<typename AoSoA_t::execution_space> exec_policy(
274 0, aosoa.size() );
275 Kokkos::parallel_for( "Cabana::deep_copy", exec_policy, assign_func );
276 Kokkos::fence();
277}
278
279//---------------------------------------------------------------------------//
288template <class DstSlice, class SrcSlice>
289inline void
290deep_copy( DstSlice& dst, const SrcSlice& src,
291 typename std::enable_if<( is_slice<DstSlice>::value &&
292 is_slice<SrcSlice>::value )>::type* = 0 )
293{
294 using dst_type = DstSlice;
295 using src_type = SrcSlice;
296
297 // Check that the data types are the same.
298 static_assert(
299 std::is_same<typename dst_type::value_type,
300 typename src_type::value_type>::value,
301 "Attempted to deep copy Slice objects of different value types" );
302
303 // Check that the element dimensions are the same.
304 static_assert( SrcSlice::view_layout::D0 == SrcSlice::view_layout::D0,
305 "Slice dimension 0 is different" );
306 static_assert( SrcSlice::view_layout::D1 == SrcSlice::view_layout::D1,
307 "Slice dimension 1 is different" );
308 static_assert( SrcSlice::view_layout::D2 == SrcSlice::view_layout::D2,
309 "Slice dimension 2 is different" );
310 static_assert( SrcSlice::view_layout::D3 == SrcSlice::view_layout::D3,
311 "Slice dimension 3 is different" );
312 static_assert( SrcSlice::view_layout::D4 == SrcSlice::view_layout::D4,
313 "Slice dimension 4 is different" );
314 static_assert( SrcSlice::view_layout::D5 == SrcSlice::view_layout::D5,
315 "Slice dimension 5 is different" );
316
317 // Check for the same number of elements.
318 if ( dst.size() != src.size() )
319 {
320 throw std::runtime_error(
321 "Attempted to deep copy Slice objects of different sizes" );
322 }
323
324 // Get the pointers to the beginning of the data blocks.
325 auto dst_data = dst.data();
326 const auto src_data = src.data();
327
328 // Return if both pointers are null.
329 if ( dst_data == nullptr && src_data == nullptr )
330 {
331 return;
332 }
333
334 // Get the number of SoA's in each object.
335 auto dst_num_soa = dst.numSoA();
336 auto src_num_soa = src.numSoA();
337
338 // Return if the slice memory occupies the same space.
339 if ( ( dst_data == src_data ) &&
340 ( dst_num_soa * dst.stride( 0 ) == src_num_soa * src.stride( 0 ) ) )
341 {
342 return;
343 }
344
345 // Get the number of components in each slice element.
346 std::size_t num_comp = 1;
347 for ( std::size_t d = 2; d < dst.viewRank(); ++d )
348 num_comp *= dst.extent( d );
349
350 // Gather the slice data in a flat view in the source space and copy it to
351 // the destination space.
352 Kokkos::View<typename dst_type::value_type*,
353 typename dst_type::memory_space>
354 gather_dst( "gather_dst", num_comp * dst.size() );
355 {
356 Kokkos::View<typename src_type::value_type*,
357 typename src_type::memory_space>
358 gather_src( "gather_src", num_comp * src.size() );
359 auto gather_func = KOKKOS_LAMBDA( const std::size_t i )
360 {
361 auto src_offset = SrcSlice::index_type::s( i ) * src.stride( 0 ) +
362 SrcSlice::index_type::a( i );
363 for ( std::size_t n = 0; n < num_comp; ++n )
364 gather_src( i * num_comp + n ) =
365 src_data[src_offset + SrcSlice::vector_length * n];
366 };
367 Kokkos::RangePolicy<typename src_type::execution_space> gather_policy(
368 0, src.size() );
369 Kokkos::parallel_for( "Cabana::deep_copy::gather", gather_policy,
370 gather_func );
371 Kokkos::fence();
372 Kokkos::deep_copy( gather_dst, gather_src );
373 }
374
375 // Scatter back into the destination slice from the gathered slice.
376 auto scatter_func = KOKKOS_LAMBDA( const std::size_t i )
377 {
378 auto dst_offset = DstSlice::index_type::s( i ) * dst.stride( 0 ) +
379 DstSlice::index_type::a( i );
380 for ( std::size_t n = 0; n < num_comp; ++n )
381 dst_data[dst_offset + DstSlice::vector_length * n] =
382 gather_dst( i * num_comp + n );
383 };
384 Kokkos::RangePolicy<typename dst_type::execution_space> scatter_policy(
385 0, dst.size() );
386 Kokkos::parallel_for( "Cabana::deep_copy::scatter", scatter_policy,
387 scatter_func );
388 Kokkos::fence();
389}
390
391//---------------------------------------------------------------------------//
398template <class Slice_t>
399inline void deep_copy( Slice_t& slice,
400 const typename Slice_t::value_type scalar )
401{
402 static_assert( is_slice<Slice_t>::value,
403 "Only slices can be assigned scalars" );
404 Kokkos::deep_copy( slice.view(), scalar );
405}
406
407//---------------------------------------------------------------------------//
415template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
416 class... FieldTags>
418 DstMemorySpace,
420 typename std::enable_if<
421 std::is_same<SrcMemorySpace, DstMemorySpace>::value>::type* = 0 )
422{
423 return plist_src;
424}
425
433template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
434 class... FieldTags>
436 DstMemorySpace,
438 typename std::enable_if<
439 !std::is_same<SrcMemorySpace, DstMemorySpace>::value>::type* = 0 )
440{
441 // Extract the original AoSoA.
442 auto aosoa_src = plist_src.aosoa();
443
444 // Create an AoSoA in the new memory space.
445 using src_plist_type =
446 ParticleList<SrcMemorySpace, VectorLength, FieldTags...>;
447 using member_types = typename src_plist_type::member_types;
449 aosoa_src.label(), aosoa_src.size() );
450
451 // Copy data to new AoAoA.
452 deep_copy( aosoa_dst, aosoa_src );
453
454 // Create new list with the copied data.
455 return ParticleList<DstMemorySpace, VectorLength, FieldTags...>(
456 aosoa_dst );
457}
458
459} // end namespace Cabana
460
461#endif // end CABANA_DEEPCOPY_HPP
Array-of-Struct-of-Arrays particle data structure.
Application-level particle storage and single particle access.
Slice a single particle property from an AoSoA.
Array-of-Struct-of-Arrays.
Definition Cabana_AoSoA.hpp:121
List of particle fields stored in AoSoA.
Definition Cabana_ParticleList.hpp:179
aosoa_type & aosoa()
Get the AoSoA.
Definition Cabana_ParticleList.hpp:221
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
AoSoA< typename SrcAoSoA::member_types, Space, SrcAoSoA::vector_length > create_mirror(const Space &, const SrcAoSoA &src, typename std::enable_if<(!std::is_same< typename SrcAoSoA::memory_space, typename Space::memory_space >::value)>::type *=0)
Allocate a mirror of the given AoSoA in the given space.
Definition Cabana_DeepCopy.hpp:38
void deep_copy(DstAoSoA &dst, const SrcAoSoA &src, typename std::enable_if<(is_aosoa< DstAoSoA >::value &&is_aosoa< SrcAoSoA >::value)>::type *=0)
Deep copy data between compatible AoSoA objects.
Definition Cabana_DeepCopy.hpp:158
SrcAoSoA create_mirror_view(const Space &, const SrcAoSoA &src, typename std::enable_if<(std::is_same< typename SrcAoSoA::memory_space, typename Space::memory_space >::value)>::type *=0)
Create a mirror view of the given AoSoA in the given space. Same space specialization returns the inp...
Definition Cabana_DeepCopy.hpp:62
AoSoA_t::template member_slice_type< M > slice(const AoSoA_t &aosoa, const std::string &slice_label="")
Create a slice from an AoSoA.
Definition Cabana_AoSoA.hpp:77
SrcAoSoA create_mirror_view_and_copy(const Space &, const SrcAoSoA &src, typename std::enable_if<(std::is_same< typename SrcAoSoA::memory_space, typename Space::memory_space >::value &&is_aosoa< SrcAoSoA >::value)>::type *=0)
Create a mirror view of the given AoSoA in the given memory space and copy the contents of the input ...
Definition Cabana_DeepCopy.hpp:108
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:861