Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_ParticleInit.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_PARTICLEINIT_HPP
17#define CABANA_PARTICLEINIT_HPP
18
19#include <Kokkos_Core.hpp>
20#include <Kokkos_Random.hpp>
21
23#include <Cabana_Slice.hpp>
24
25#include <random>
26#include <type_traits>
27
28namespace Cabana
29{
30
31namespace Impl
32{
34template <class ArrayType>
35auto copyArray( ArrayType corner )
36{
37 using value_type = std::remove_reference_t<decltype( corner[0] )>;
38 Kokkos::Array<value_type, 3> kokkos_corner;
39 for ( std::size_t d = 0; d < 3; ++d )
40 kokkos_corner[d] = corner[d];
41
42 return kokkos_corner;
43}
44
45} // namespace Impl
46
47//---------------------------------------------------------------------------//
48// Initialization type tags.
49
52{
53};
54
56{
57};
58
59//---------------------------------------------------------------------------//
60// Fully random
61//---------------------------------------------------------------------------//
62
63//---------------------------------------------------------------------------//
86template <class ExecutionSpace, class InitFunctor, class ParticleListType,
87 class ArrayType>
89 InitRandom, ExecutionSpace exec_space, const InitFunctor& create_functor,
90 ParticleListType& particle_list, const std::size_t num_particles,
91 const ArrayType box_min, const ArrayType box_max,
92 const std::size_t previous_num_particles = 0,
93 const bool shrink_to_fit = true, const uint64_t seed = 342343901,
94 typename std::enable_if<is_particle_list<ParticleListType>::value,
95 int>::type* = 0 )
96{
97 // Memory space.
98 using memory_space = typename ParticleListType::memory_space;
99
100 using PoolType = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
101 using RandomType = Kokkos::Random_XorShift64<ExecutionSpace>;
102 PoolType pool( seed );
103
104 // Resize the aosoa prior to lambda capture.
105 auto& aosoa = particle_list.aosoa();
106 aosoa.resize( previous_num_particles + num_particles );
107
108 // Creation count.
109 auto count = Kokkos::View<int*, memory_space>( "particle_count", 1 );
110 Kokkos::deep_copy( count, previous_num_particles );
111
112 // Copy corners to device accessible arrays.
113 auto kokkos_min = Impl::copyArray( box_min );
114 auto kokkos_max = Impl::copyArray( box_max );
115
116 auto random_coord_op = KOKKOS_LAMBDA( const int p )
117 {
118 // Particle coordinate.
119 double px[3];
120
121 auto gen = pool.get_state();
122 auto particle = particle_list.getParticle( p );
123 for ( int d = 0; d < 3; ++d )
124 px[d] = Kokkos::rand<RandomType, double>::draw( gen, kokkos_min[d],
125 kokkos_max[d] );
126 pool.free_state( gen );
127
128 // No volume information, so pass zero.
129 int create = create_functor( count( 0 ), px, 0.0, particle );
130
131 // If we created a new particle insert it into the list.
132 if ( create )
133 {
134 auto c = Kokkos::atomic_fetch_add( &count( 0 ), 1 );
135 particle_list.setParticle( particle, c );
136 }
137 };
138
139 Kokkos::RangePolicy<ExecutionSpace> exec_policy(
140 exec_space, previous_num_particles,
141 previous_num_particles + num_particles );
142 Kokkos::parallel_for( "Cabana::createParticles", exec_policy,
143 random_coord_op );
144 Kokkos::fence();
145
146 auto count_host =
147 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), count );
148 aosoa.resize( count_host( 0 ) );
149 if ( shrink_to_fit )
150 aosoa.shrinkToFit();
151 return count_host( 0 );
152}
153
154//---------------------------------------------------------------------------//
177template <class InitFunctor, class ParticleListType, class ArrayType>
178int createParticles( InitRandom tag, const InitFunctor& create_functor,
179 ParticleListType& particle_list,
180 const std::size_t num_particles, const ArrayType box_min,
181 const ArrayType box_max,
182 const std::size_t previous_num_particles = 0,
183 const bool shrink_to_fit = true,
184 const uint64_t seed = 342343901 )
185{
186 using exec_space = typename ParticleListType::memory_space::execution_space;
187 return createParticles( tag, exec_space{}, create_functor, particle_list,
188 num_particles, box_min, box_max,
189 previous_num_particles, shrink_to_fit, seed );
190}
191
204template <class ExecutionSpace, class PositionType, class ArrayType>
206 InitRandom, ExecutionSpace exec_space, PositionType& positions,
207 const std::size_t num_particles, const ArrayType box_min,
208 const ArrayType box_max, const std::size_t previous_num_particles = 0,
209 const uint64_t seed = 342343901,
210 typename std::enable_if<( is_slice<PositionType>::value ||
211 Kokkos::is_view<PositionType>::value ),
212 int>::type* = 0 )
213{
214 // Ensure correct space for the particles (View or Slice).
215 checkSize( positions, num_particles + previous_num_particles );
216
217 // Copy corners to device accessible arrays.
218 auto kokkos_min = Impl::copyArray( box_min );
219 auto kokkos_max = Impl::copyArray( box_max );
220
221 using PoolType = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
222 using RandomType = Kokkos::Random_XorShift64<ExecutionSpace>;
223 PoolType pool( seed );
224 auto random_coord_op = KOKKOS_LAMBDA( const int p )
225 {
226 auto gen = pool.get_state();
227 for ( int d = 0; d < 3; ++d )
228 positions( p, d ) = Kokkos::rand<RandomType, double>::draw(
229 gen, kokkos_min[d], kokkos_max[d] );
230 pool.free_state( gen );
231 };
232
233 Kokkos::RangePolicy<ExecutionSpace> exec_policy(
234 exec_space, previous_num_particles,
235 previous_num_particles + num_particles );
236 Kokkos::parallel_for( "Cabana::createParticles", exec_policy,
237 random_coord_op );
238 Kokkos::fence();
239}
240
253template <class PositionType, class ArrayType>
255 InitRandom tag, PositionType& positions, const std::size_t num_particles,
256 const ArrayType box_min, const ArrayType box_max,
257 const std::size_t previous_num_particles = 0,
258 const uint64_t seed = 342343901,
259 typename std::enable_if<( is_slice<PositionType>::value ||
260 Kokkos::is_view<PositionType>::value ),
261 int>::type* = 0 )
262{
263 using exec_space = typename PositionType::execution_space;
264 createParticles( tag, exec_space{}, positions, num_particles, box_min,
265 box_max, previous_num_particles, seed );
266}
267
268//---------------------------------------------------------------------------//
269// Random with minimum separation
270//---------------------------------------------------------------------------//
271
300template <class ExecutionSpace, class InitFunctor, class ParticleListType,
301 class PositionTag, class ArrayType>
303 InitRandom tag, ExecutionSpace exec_space,
304 const InitFunctor& create_functor, ParticleListType& particle_list,
305 PositionTag position_tag, const std::size_t num_particles,
306 const double min_dist, const ArrayType box_min, const ArrayType box_max,
307 const std::size_t previous_num_particles = 0,
308 const bool shrink_to_fit = true, const uint64_t seed = 342343901,
309 typename std::enable_if<is_particle_list<ParticleListType>::value,
310 int>::type* = 0 )
311{
312 double min_dist_sqr = min_dist * min_dist;
313
314 // Resize the aosoa prior to lambda capture.
315 auto& aosoa = particle_list.aosoa();
316 aosoa.resize( previous_num_particles + num_particles );
317
318 auto positions = particle_list.slice( position_tag );
319
320 // Create the functor which ignores particles within the radius of another.
321 auto min_distance_op =
322 KOKKOS_LAMBDA( const int id, const double px[3], const double,
323 typename ParticleListType::particle_type& particle )
324 {
325 // Ensure this particle is not within the minimum distance of any other
326 // existing particle.
327 for ( int n = 0; n < id; n++ )
328 {
329 double dx = positions( n, 0 ) - px[0];
330 double dy = positions( n, 1 ) - px[1];
331 double dz = positions( n, 2 ) - px[2];
332 double dist = dx * dx + dy * dy + dz * dz;
333 if ( dist < min_dist_sqr )
334 return false;
335 }
336
337 bool create = create_functor( id, px, 0.0, particle );
338 return create;
339 };
340
341 // Pass the functor to the general case.
342 return createParticles( tag, exec_space, min_distance_op, particle_list,
343 num_particles, box_min, box_max,
344 previous_num_particles, shrink_to_fit, seed );
345}
346
374template <class InitFunctor, class ParticleListType, class PositionTag,
375 class ArrayType>
376int createParticles( InitRandom tag, const InitFunctor& create_functor,
377 ParticleListType& particle_list, PositionTag position_tag,
378 const std::size_t num_particles, const double min_dist,
379 const ArrayType box_min, const ArrayType box_max,
380 const std::size_t previous_num_particles = 0,
381 const bool shrink_to_fit = true,
382 const uint64_t seed = 342343901 )
383{
384 using exec_space = typename ParticleListType::memory_space::execution_space;
385 return createParticles( tag, exec_space{}, create_functor, particle_list,
386 position_tag, num_particles, min_dist, box_min,
387 box_max, previous_num_particles, shrink_to_fit,
388 seed );
389}
390
391} // namespace Cabana
392
393#endif
auto copyArray(ArrayType corner)
Copy array (std, c-array) into Kokkos::Array for potential device use.
Definition Cabana_ParticleInit.hpp:35
Application-level particle storage and single particle access.
Slice a single particle property from an AoSoA.
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
int createParticles(InitRandom, ExecutionSpace exec_space, const InitFunctor &create_functor, ParticleListType &particle_list, const std::size_t num_particles, const ArrayType box_min, const ArrayType box_max, const std::size_t previous_num_particles=0, const bool shrink_to_fit=true, const uint64_t seed=342343901, typename std::enable_if< is_particle_list< ParticleListType >::value, int >::type *=0)
Initialize random particles given an initialization functor.
Definition Cabana_ParticleInit.hpp:88
void checkSize(SliceType slice, const std::size_t size, typename std::enable_if< is_slice< SliceType >::value, int >::type *=0)
Check slice size (differs from Kokkos View).
Definition Cabana_Slice.hpp:990
Random particle initialization type tag.
Definition Cabana_ParticleInit.hpp:56
Uniform particle initialization type tag.
Definition Cabana_ParticleInit.hpp:52
ParticleList static type checker.
Definition Cabana_ParticleList.hpp:282
Slice static type checker.
Definition Cabana_Slice.hpp:861