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 std::enable_if_t<( !std::is_same_v<typename SrcAoSoA::memory_space,
41 typename Space::memory_space> )>* =
42 nullptr )
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 std::enable_if_t<( std::is_same_v<typename SrcAoSoA::memory_space,
65 typename Space::memory_space> )>* =
66 nullptr )
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 std::enable_if_t<( !std::is_same_v<typename SrcAoSoA::memory_space,
88 typename Space::memory_space> )>* =
89 nullptr )
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 std::enable_if_t<( std::is_same_v<typename SrcAoSoA::memory_space,
111 typename Space::memory_space> &&
112 is_aosoa<SrcAoSoA>::value )>* = nullptr )
113{
114 return src;
115}
116
117//---------------------------------------------------------------------------//
128template <class Space, class SrcAoSoA>
129inline AoSoA<typename SrcAoSoA::member_types, Space, SrcAoSoA::vector_length>
131 const Space& space, const SrcAoSoA& src,
132 std::enable_if_t<( !std::is_same_v<typename SrcAoSoA::memory_space,
133 typename Space::memory_space> &&
134 is_aosoa<SrcAoSoA>::value )>* = nullptr )
135{
136 auto dst = create_mirror( space, src );
137
138 Kokkos::deep_copy(
139 typename decltype( dst )::soa_view( dst.data(), dst.numSoA() ),
140 typename SrcAoSoA::soa_view( src.data(), src.numSoA() ) );
141
142 return dst;
143}
144
145//---------------------------------------------------------------------------//
154template <class DstAoSoA, class SrcAoSoA>
155inline void
156deep_copy( DstAoSoA& dst, const SrcAoSoA& src,
157 std::enable_if_t<( is_aosoa<DstAoSoA>::value &&
158 is_aosoa<SrcAoSoA>::value )>* = nullptr )
159{
160 using dst_type = DstAoSoA;
161 using src_type = SrcAoSoA;
162 using dst_memory_space = typename dst_type::memory_space;
163 using src_memory_space = typename src_type::memory_space;
164 using dst_soa_type = typename dst_type::soa_type;
165 using src_soa_type = typename src_type::soa_type;
166
167 // Check that the data types are the same.
168 static_assert( std::is_same_v<typename dst_type::member_types,
169 typename src_type::member_types>,
170 "Cabana::deep_copy: Attempted to deep copy AoSoA objects of "
171 "different member types" );
172
173 // Check for the same number of values.
174 if ( dst.size() != src.size() )
175 {
176 throw std::runtime_error(
177 "Cabana::deep_copy: Attempted to deep copy "
178 "AoSoA objects of different sizes. (Labels: " +
179 src.label() + ", " + dst.label() + ")" );
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_v<dst_soa_type, src_soa_type> )
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 "Cabana::deep_copy: 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 std::enable_if_t<( is_slice<DstSlice>::value &&
292 is_slice<SrcSlice>::value )>* = nullptr )
293{
294 using dst_type = DstSlice;
295 using src_type = SrcSlice;
296
297 // Check that the data types are the same.
298 static_assert( std::is_same_v<typename dst_type::value_type,
299 typename src_type::value_type>,
300 "Cabana::deep_copy: Attempted to deep copy Slice objects of "
301 "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 "Cabana::deep_copy: Slice dimension 0 is different" );
306 static_assert( SrcSlice::view_layout::D1 == SrcSlice::view_layout::D1,
307 "Cabana::deep_copy: Slice dimension 1 is different" );
308 static_assert( SrcSlice::view_layout::D2 == SrcSlice::view_layout::D2,
309 "Cabana::deep_copy: Slice dimension 2 is different" );
310 static_assert( SrcSlice::view_layout::D3 == SrcSlice::view_layout::D3,
311 "Cabana::deep_copy: Slice dimension 3 is different" );
312 static_assert( SrcSlice::view_layout::D4 == SrcSlice::view_layout::D4,
313 "Cabana::deep_copy: Slice dimension 4 is different" );
314 static_assert( SrcSlice::view_layout::D5 == SrcSlice::view_layout::D5,
315 "Cabana::deep_copy: 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 "Cabana::deep_copy: Attempted to deep copy Slice objects of "
322 "different sizes. (Labels: " +
323 src.label() + ", " + dst.label() + ")" );
324 }
325
326 // Get the pointers to the beginning of the data blocks.
327 auto dst_data = dst.data();
328 const auto src_data = src.data();
329
330 // Return if both pointers are null.
331 if ( dst_data == nullptr && src_data == nullptr )
332 {
333 return;
334 }
335
336 // Get the number of SoA's in each object.
337 auto dst_num_soa = dst.numSoA();
338 auto src_num_soa = src.numSoA();
339
340 // Return if the slice memory occupies the same space.
341 if ( ( dst_data == src_data ) &&
342 ( dst_num_soa * dst.stride( 0 ) == src_num_soa * src.stride( 0 ) ) )
343 {
344 return;
345 }
346
347 // Get the number of components in each slice element.
348 std::size_t num_comp = 1;
349 for ( std::size_t d = 2; d < dst.viewRank(); ++d )
350 num_comp *= dst.extent( d );
351
352 // Gather the slice data in a flat view in the source space and copy it to
353 // the destination space.
354 Kokkos::View<typename dst_type::value_type*,
355 typename dst_type::memory_space>
356 gather_dst( "gather_dst", num_comp * dst.size() );
357 {
358 Kokkos::View<typename src_type::value_type*,
359 typename src_type::memory_space>
360 gather_src( "gather_src", num_comp * src.size() );
361 auto gather_func = KOKKOS_LAMBDA( const std::size_t i )
362 {
363 auto src_offset = SrcSlice::index_type::s( i ) * src.stride( 0 ) +
364 SrcSlice::index_type::a( i );
365 for ( std::size_t n = 0; n < num_comp; ++n )
366 gather_src( i * num_comp + n ) =
367 src_data[src_offset + SrcSlice::vector_length * n];
368 };
369 Kokkos::RangePolicy<typename src_type::execution_space> gather_policy(
370 0, src.size() );
371 Kokkos::parallel_for( "Cabana::deep_copy::gather", gather_policy,
372 gather_func );
373 Kokkos::fence();
374 Kokkos::deep_copy( gather_dst, gather_src );
375 }
376
377 // Scatter back into the destination slice from the gathered slice.
378 auto scatter_func = KOKKOS_LAMBDA( const std::size_t i )
379 {
380 auto dst_offset = DstSlice::index_type::s( i ) * dst.stride( 0 ) +
381 DstSlice::index_type::a( i );
382 for ( std::size_t n = 0; n < num_comp; ++n )
383 dst_data[dst_offset + DstSlice::vector_length * n] =
384 gather_dst( i * num_comp + n );
385 };
386 Kokkos::RangePolicy<typename dst_type::execution_space> scatter_policy(
387 0, dst.size() );
388 Kokkos::parallel_for( "Cabana::deep_copy::scatter", scatter_policy,
389 scatter_func );
390 Kokkos::fence();
391}
392
393//---------------------------------------------------------------------------//
400template <class Slice_t>
401inline void deep_copy( Slice_t& slice,
402 const typename Slice_t::value_type scalar )
403{
404 static_assert( is_slice<Slice_t>::value,
405 "Cabana::deep_copy: Only slices can be assigned scalars" );
406 Kokkos::deep_copy( slice.view(), scalar );
407}
408
409//---------------------------------------------------------------------------//
417template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
418 class... FieldTags>
420 DstMemorySpace,
422 std::enable_if_t<std::is_same_v<SrcMemorySpace, DstMemorySpace>>* =
423 nullptr )
424{
425 return plist_src;
426}
427
435template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
436 class... FieldTags>
438 DstMemorySpace,
440 std::enable_if_t<!std::is_same_v<SrcMemorySpace, DstMemorySpace>>* =
441 nullptr )
442{
443 // Extract the original AoSoA.
444 auto aosoa_src = plist_src.aosoa();
445
446 // Create an AoSoA in the new memory space.
447 using src_plist_type =
448 ParticleList<SrcMemorySpace, VectorLength, FieldTags...>;
449 using member_types = typename src_plist_type::member_types;
451 aosoa_src.label(), aosoa_src.size() );
452
453 // Copy data to new AoAoA.
454 deep_copy( aosoa_dst, aosoa_src );
455
456 // Create new list with the copied data.
457 return ParticleList<DstMemorySpace, VectorLength, FieldTags...>(
458 aosoa_dst );
459}
460
461} // end namespace Cabana
462
463#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:123
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, std::enable_if_t<(!std::is_same_v< typename SrcAoSoA::memory_space, typename Space::memory_space >)> *=nullptr)
Allocate a mirror of the given AoSoA in the given space.
Definition Cabana_DeepCopy.hpp:38
SrcAoSoA create_mirror_view_and_copy(const Space &, const SrcAoSoA &src, std::enable_if_t<(std::is_same_v< typename SrcAoSoA::memory_space, typename Space::memory_space > &&is_aosoa< SrcAoSoA >::value)> *=nullptr)
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
SrcAoSoA create_mirror_view(const Space &, const SrcAoSoA &src, std::enable_if_t<(std::is_same_v< typename SrcAoSoA::memory_space, typename Space::memory_space >)> *=nullptr)
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
void deep_copy(DstAoSoA &dst, const SrcAoSoA &src, std::enable_if_t<(is_aosoa< DstAoSoA >::value &&is_aosoa< SrcAoSoA >::value)> *=nullptr)
Deep copy data between compatible AoSoA objects.
Definition Cabana_DeepCopy.hpp:156
AoSoA static type checker.
Definition Cabana_AoSoA.hpp:61
Slice static type checker.
Definition Cabana_Slice.hpp:861