Cabana 0.8.99-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 for the same number of elements.
304 if ( dst.size() != src.size() )
305 {
306 throw std::runtime_error(
307 "Cabana::deep_copy: Attempted to deep copy Slice objects of "
308 "different sizes. (Labels: " +
309 src.label() + ", " + dst.label() + ")" );
310 }
311
312 // Get the pointers to the beginning of the data blocks.
313 auto dst_data = dst.data();
314 const auto src_data = src.data();
315
316 // Return if both pointers are null.
317 if ( dst_data == nullptr && src_data == nullptr )
318 {
319 return;
320 }
321
322 // Get the number of SoA's in each object.
323 auto dst_num_soa = dst.numSoA();
324 auto src_num_soa = src.numSoA();
325
326 // Return if the slice memory occupies the same space.
327 if ( ( dst_data == src_data ) &&
328 ( dst_num_soa * dst.stride( 0 ) == src_num_soa * src.stride( 0 ) ) )
329 {
330 return;
331 }
332
333 // Get the number of components in each slice element.
334 std::size_t num_comp = 1;
335 for ( std::size_t d = 2; d < dst.viewRank(); ++d )
336 num_comp *= dst.extent( d );
337
338 // Gather the slice data in a flat view in the source space and copy it to
339 // the destination space.
340 Kokkos::View<typename dst_type::value_type*,
341 typename dst_type::memory_space>
342 gather_dst( "gather_dst", num_comp * dst.size() );
343 {
344 Kokkos::View<typename src_type::value_type*,
345 typename src_type::memory_space>
346 gather_src( "gather_src", num_comp * src.size() );
347 auto gather_func = KOKKOS_LAMBDA( const std::size_t i )
348 {
349 auto src_offset = SrcSlice::index_type::s( i ) * src.stride( 0 ) +
350 SrcSlice::index_type::a( i );
351 for ( std::size_t n = 0; n < num_comp; ++n )
352 gather_src( i * num_comp + n ) =
353 src_data[src_offset + SrcSlice::vector_length * n];
354 };
355 Kokkos::RangePolicy<typename src_type::execution_space> gather_policy(
356 0, src.size() );
357 Kokkos::parallel_for( "Cabana::deep_copy::gather", gather_policy,
358 gather_func );
359 Kokkos::fence();
360 Kokkos::deep_copy( gather_dst, gather_src );
361 }
362
363 // Scatter back into the destination slice from the gathered slice.
364 auto scatter_func = KOKKOS_LAMBDA( const std::size_t i )
365 {
366 auto dst_offset = DstSlice::index_type::s( i ) * dst.stride( 0 ) +
367 DstSlice::index_type::a( i );
368 for ( std::size_t n = 0; n < num_comp; ++n )
369 dst_data[dst_offset + DstSlice::vector_length * n] =
370 gather_dst( i * num_comp + n );
371 };
372 Kokkos::RangePolicy<typename dst_type::execution_space> scatter_policy(
373 0, dst.size() );
374 Kokkos::parallel_for( "Cabana::deep_copy::scatter", scatter_policy,
375 scatter_func );
376 Kokkos::fence();
377}
378
379//---------------------------------------------------------------------------//
386template <class Slice_t>
387inline void deep_copy( Slice_t& slice,
388 const typename Slice_t::value_type scalar )
389{
390 static_assert( is_slice<Slice_t>::value,
391 "Cabana::deep_copy: Only slices can be assigned scalars" );
392 Kokkos::deep_copy( slice.view(), scalar );
393}
394
395//---------------------------------------------------------------------------//
403template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
404 class... FieldTags>
406 DstMemorySpace,
408 std::enable_if_t<std::is_same_v<SrcMemorySpace, DstMemorySpace>>* =
409 nullptr )
410{
411 return plist_src;
412}
413
421template <class DstMemorySpace, class SrcMemorySpace, int VectorLength,
422 class... FieldTags>
424 DstMemorySpace,
426 std::enable_if_t<!std::is_same_v<SrcMemorySpace, DstMemorySpace>>* =
427 nullptr )
428{
429 // Extract the original AoSoA.
430 auto aosoa_src = plist_src.aosoa();
431
432 // Create an AoSoA in the new memory space.
433 using src_plist_type =
434 ParticleList<SrcMemorySpace, VectorLength, FieldTags...>;
435 using member_types = typename src_plist_type::member_types;
437 aosoa_src.label(), aosoa_src.size() );
438
439 // Copy data to new AoAoA.
440 deep_copy( aosoa_dst, aosoa_src );
441
442 // Create new list with the copied data.
443 return ParticleList<DstMemorySpace, VectorLength, FieldTags...>(
444 aosoa_dst );
445}
446
447} // end namespace Cabana
448
449#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:532