Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_Grid_ParticleInit.hpp
Go to the documentation of this file.
1/****************************************************************************
2 * Copyright (c) 2018-2022 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
12/****************************************************************************
13 * Copyright (c) 2021 by the Picasso authors *
14 * All rights reserved. *
15 * *
16 * This file is part of the Picasso library. Picasso is distributed under a *
17 * BSD 3-clause license. For the licensing terms see the LICENSE file in *
18 * the top-level directory. *
19 * *
20 * SPDX-License-Identifier: BSD-3-Clause *
21 ****************************************************************************/
22
27#ifndef CAJITA_PARTICLEINIT_HPP
28#define CAJITA_PARTICLEINIT_HPP
29
32
34#include <Cabana_Slice.hpp>
35
36#include <Kokkos_Core.hpp>
37#include <Kokkos_Random.hpp>
38
39#include <exception>
40
41namespace Cabana
42{
43namespace Grid
44{
45//---------------------------------------------------------------------------//
66template <class ExecutionSpace, class InitFunctor, class ParticleListType,
67 class LocalGridType>
69 Cabana::InitRandom, const ExecutionSpace& exec_space,
70 const InitFunctor& create_functor, ParticleListType& particle_list,
71 const int particles_per_cell, LocalGridType& local_grid,
72 const std::size_t previous_num_particles = 0,
73 const bool shrink_to_fit = true, const uint64_t seed = 123456,
74 typename std::enable_if<is_particle_list<ParticleListType>::value,
75 int>::type* = 0 )
76{
77 // Memory space.
78 using memory_space = typename ParticleListType::memory_space;
79
80 // Create a local mesh.
81 auto local_mesh = createLocalMesh<memory_space>( local_grid );
82
83 // Get the global grid.
84 const auto& global_grid = local_grid.globalGrid();
85
86 // Get the local set of owned cell indices.
87 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
88
89 // Create a random number generator.
90 const auto local_seed = seed + global_grid.blockId();
91 using rnd_type = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
92 // FIXME: remove when 4.7 required
93#if ( KOKKOS_VERSION < 40700 )
94 rnd_type pool;
95 pool.init( local_seed, owned_cells.size() );
96#else
97 rnd_type pool( local_seed, owned_cells.size() );
98#endif
99
100 // Get the aosoa.
101 auto& aosoa = particle_list.aosoa();
102
103 // Allocate enough space for the case the particles consume the entire
104 // local grid.
105 int num_particles = particles_per_cell * owned_cells.size();
106 aosoa.resize( previous_num_particles + num_particles );
107
108 // Creation count (start from previous).
109 auto count = Kokkos::View<int*, memory_space>( "particle_count", 1 );
110 Kokkos::deep_copy( count, previous_num_particles );
111
112 // Initialize particles.
114 "Cabana::Grid::ParticleInit::Random", exec_space, owned_cells,
115 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
116 // Compute the owned local cell id.
117 int i_own = i - owned_cells.min( Dim::I );
118 int j_own = j - owned_cells.min( Dim::J );
119 int k_own = k - owned_cells.min( Dim::K );
120 int cell_id =
121 i_own + owned_cells.extent( Dim::I ) *
122 ( j_own + k_own * owned_cells.extent( Dim::J ) );
123
124 // Get the coordinates of the low cell node.
125 int low_node[3] = { i, j, k };
126 double low_coords[3];
127 local_mesh.coordinates( Node(), low_node, low_coords );
128
129 // Get the coordinates of the high cell node.
130 int high_node[3] = { i + 1, j + 1, k + 1 };
131 double high_coords[3];
132 local_mesh.coordinates( Node(), high_node, high_coords );
133
134 // Random number generator.
135 auto rand = pool.get_state( cell_id );
136
137 // Particle coordinate.
138 double px[3];
139
140 // Particle volume.
141 double pv =
142 local_mesh.measure( Cell(), low_node ) / particles_per_cell;
143
144 // Create particles.
145 for ( int p = 0; p < particles_per_cell; ++p )
146 {
147 // Local particle id.
148 int pid =
149 previous_num_particles + cell_id * particles_per_cell + p;
150
151 // Select a random point in the cell for the particle
152 // location. These coordinates are logical.
153 for ( int d = 0; d < 3; ++d )
154 {
155 px[d] = Kokkos::rand<decltype( rand ), double>::draw(
156 rand, low_coords[d], high_coords[d] );
157 }
158
159 // Create a new particle with the given logical coordinates.
160 auto particle = particle_list.getParticle( pid );
161 bool created = create_functor( pid, px, pv, particle );
162
163 // If we created a new particle insert it into the list.
164 if ( created )
165 {
166 auto c = Kokkos::atomic_fetch_add( &count( 0 ), 1 );
167 particle_list.setParticle( particle, c );
168 }
169 }
170 } );
171 Kokkos::fence();
172
173 auto count_host =
174 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), count );
175 aosoa.resize( count_host( 0 ) );
176 if ( shrink_to_fit )
177 aosoa.shrinkToFit();
178 return count_host( 0 );
179}
180
200template <class InitFunctor, class ParticleListType, class LocalGridType>
202 Cabana::InitRandom tag, const InitFunctor& create_functor,
203 ParticleListType& particle_list, const int particles_per_cell,
204 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
205 const bool shrink_to_fit = true, const uint64_t seed = 123456,
206 typename std::enable_if<is_particle_list<ParticleListType>::value,
207 int>::type* = 0 )
208{
209 using exec_space = typename ParticleListType::memory_space::execution_space;
210 return createParticles( tag, exec_space{}, create_functor, particle_list,
211 particles_per_cell, local_grid,
212 previous_num_particles, shrink_to_fit, seed );
213}
214
215//---------------------------------------------------------------------------//
228template <class ExecutionSpace, class PositionType, class LocalGridType>
230 Cabana::InitRandom, const ExecutionSpace& exec_space,
231 PositionType& positions, const int particles_per_cell,
232 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
233 const uint64_t seed = 123456,
234 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
235 Kokkos::is_view<PositionType>::value ),
236 int>::type* = 0 )
237{
238 // Memory space.
239 using memory_space = typename PositionType::memory_space;
240
241 // Create a local mesh.
242 auto local_mesh = createLocalMesh<memory_space>( local_grid );
243
244 // Get the global grid.
245 const auto& global_grid = local_grid.globalGrid();
246
247 // Get the local set of owned cell indices.
248 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
249
250 // Create a random number generator.
251 const auto local_seed = seed + global_grid.blockId();
252 using rnd_type = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
253 // FIXME: remove when 4.7 required
254#if ( KOKKOS_VERSION < 40700 )
255 rnd_type pool;
256 pool.init( local_seed, owned_cells.size() );
257#else
258 rnd_type pool( local_seed, owned_cells.size() );
259#endif
260
261 // Ensure correct space for the particles.
262 assert( positions.size() == static_cast<std::size_t>( particles_per_cell *
263 owned_cells.size() ) +
264 previous_num_particles );
265
266 // Initialize particles.
268 "Cabana::Grid::ParticleInit::Random", exec_space, owned_cells,
269 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
270 // Compute the owned local cell id.
271 int i_own = i - owned_cells.min( Dim::I );
272 int j_own = j - owned_cells.min( Dim::J );
273 int k_own = k - owned_cells.min( Dim::K );
274 int cell_id =
275 i_own + owned_cells.extent( Dim::I ) *
276 ( j_own + k_own * owned_cells.extent( Dim::J ) );
277
278 // Get the coordinates of the low cell node.
279 int low_node[3] = { i, j, k };
280 double low_coords[3];
281 local_mesh.coordinates( Node(), low_node, low_coords );
282
283 // Get the coordinates of the high cell node.
284 int high_node[3] = { i + 1, j + 1, k + 1 };
285 double high_coords[3];
286 local_mesh.coordinates( Node(), high_node, high_coords );
287
288 // Random number generator.
289 auto rand = pool.get_state( cell_id );
290
291 // Create particles.
292 for ( int p = 0; p < particles_per_cell; ++p )
293 {
294 // Local particle id.
295 int pid =
296 previous_num_particles + cell_id * particles_per_cell + p;
297
298 // Select a random point in the cell for the particle
299 // location. These coordinates are logical.
300 for ( int d = 0; d < 3; ++d )
301 {
302 positions( pid, d ) =
303 Kokkos::rand<decltype( rand ), double>::draw(
304 rand, low_coords[d], high_coords[d] );
305 }
306 }
307 } );
308}
309
322template <class PositionType, class LocalGridType>
324 Cabana::InitRandom tag, PositionType& positions,
325 const int particles_per_cell, LocalGridType& local_grid,
326 const std::size_t previous_num_particles = 0, const uint64_t seed = 123456,
327 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
328 Kokkos::is_view<PositionType>::value ),
329 int>::type* = 0 )
330{
331 using exec_space = typename PositionType::execution_space;
332 createParticles( tag, exec_space{}, positions, particles_per_cell,
333 local_grid, previous_num_particles, seed );
334}
335
336//---------------------------------------------------------------------------//
358template <class ExecutionSpace, class InitFunctor, class ParticleListType,
359 class LocalGridType>
361 Cabana::InitUniform, const ExecutionSpace& exec_space,
362 const InitFunctor& create_functor, ParticleListType& particle_list,
363 const int particles_per_cell_dim, LocalGridType& local_grid,
364 const std::size_t previous_num_particles = 0,
365 const bool shrink_to_fit = true,
366 typename std::enable_if<is_particle_list<ParticleListType>::value,
367 int>::type* = 0 )
368{
369 // Memory space.
370 using memory_space = typename ParticleListType::memory_space;
371
372 // Create a local mesh.
373 auto local_mesh = createLocalMesh<memory_space>( local_grid );
374
375 // Get the local set of owned cell indices.
376 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
377
378 // Get the aosoa.
379 auto& aosoa = particle_list.aosoa();
380
381 // Allocate enough space for particles fill the entire local grid.
382 int particles_per_cell = particles_per_cell_dim * particles_per_cell_dim *
383 particles_per_cell_dim;
384 int num_particles = particles_per_cell * owned_cells.size();
385 aosoa.resize( previous_num_particles + num_particles );
386
387 // Creation count (start from previous).
388 auto count = Kokkos::View<int*, memory_space>( "particle_count", 1 );
389 Kokkos::deep_copy( count, previous_num_particles );
390
391 // Initialize particles.
393 "Cabana::Grid::ParticleInit::Uniform", exec_space, owned_cells,
394 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
395 // Compute the owned local cell id.
396 int i_own = i - owned_cells.min( Dim::I );
397 int j_own = j - owned_cells.min( Dim::J );
398 int k_own = k - owned_cells.min( Dim::K );
399 int cell_id =
400 i_own + owned_cells.extent( Dim::I ) *
401 ( j_own + k_own * owned_cells.extent( Dim::J ) );
402
403 // Get the coordinates of the low cell node.
404 int low_node[3] = { i, j, k };
405 double low_coords[3];
406 local_mesh.coordinates( Node(), low_node, low_coords );
407
408 // Get the coordinates of the high cell node.
409 int high_node[3] = { i + 1, j + 1, k + 1 };
410 double high_coords[3];
411 local_mesh.coordinates( Node(), high_node, high_coords );
412
413 // Compute the particle spacing in each dimension.
414 double spacing[3] = { ( high_coords[Dim::I] - low_coords[Dim::I] ) /
415 particles_per_cell_dim,
416 ( high_coords[Dim::J] - low_coords[Dim::J] ) /
417 particles_per_cell_dim,
418 ( high_coords[Dim::K] - low_coords[Dim::K] ) /
419 particles_per_cell_dim };
420
421 // Particle coordinate.
422 double px[3];
423
424 // Particle volume.
425 double pv =
426 local_mesh.measure( Cell(), low_node ) / particles_per_cell;
427
428 // Create particles.
429 for ( int ip = 0; ip < particles_per_cell_dim; ++ip )
430 for ( int jp = 0; jp < particles_per_cell_dim; ++jp )
431 for ( int kp = 0; kp < particles_per_cell_dim; ++kp )
432 {
433 // Local particle id.
434 int pid = previous_num_particles +
435 cell_id * particles_per_cell + ip +
436 particles_per_cell_dim *
437 ( jp + particles_per_cell_dim * kp );
438
439 // Set the particle position in logical coordinates.
440 px[Dim::I] = 0.5 * spacing[Dim::I] +
441 ip * spacing[Dim::I] + low_coords[Dim::I];
442 px[Dim::J] = 0.5 * spacing[Dim::J] +
443 jp * spacing[Dim::J] + low_coords[Dim::J];
444 px[Dim::K] = 0.5 * spacing[Dim::K] +
445 kp * spacing[Dim::K] + low_coords[Dim::K];
446
447 // Create a new particle with the given logical
448 // coordinates.
449 auto particle = particle_list.getParticle( pid );
450 bool created = create_functor( pid, px, pv, particle );
451
452 // If we created a new particle insert it into the list.
453 if ( created )
454 {
455 // TODO: replace atomic with fill (use pid directly)
456 // and filter of empty list entries.
457 auto c = Kokkos::atomic_fetch_add( &count( 0 ), 1 );
458 particle_list.setParticle( particle, c );
459 }
460 }
461 } );
462 Kokkos::fence();
463
464 auto count_host =
465 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), count );
466 aosoa.resize( count_host( 0 ) );
467 if ( shrink_to_fit )
468 aosoa.shrinkToFit();
469 return count_host( 0 );
470}
471
491template <class InitFunctor, class ParticleListType, class LocalGridType>
493 Cabana::InitUniform tag, const InitFunctor& create_functor,
494 ParticleListType& particle_list, const int particles_per_cell_dim,
495 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
496 const bool shrink_to_fit = true,
497 typename std::enable_if<is_particle_list<ParticleListType>::value,
498 int>::type* = 0 )
499{
500 using exec_space = typename ParticleListType::memory_space::execution_space;
501 return createParticles( tag, exec_space{}, create_functor, particle_list,
502 particles_per_cell_dim, local_grid,
503 previous_num_particles, shrink_to_fit );
504}
505
506//---------------------------------------------------------------------------//
519template <class ExecutionSpace, class PositionType, class LocalGridType>
521 Cabana::InitUniform, const ExecutionSpace& exec_space,
522 PositionType& positions, const int particles_per_cell_dim,
523 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
524 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
525 Kokkos::is_view<PositionType>::value ),
526 int>::type* = 0 )
527{
528 // Memory space.
529 using memory_space = typename PositionType::memory_space;
530
531 // Create a local mesh.
532 auto local_mesh = createLocalMesh<memory_space>( local_grid );
533
534 // Get the local set of owned cell indices.
535 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
536
537 int particles_per_cell = particles_per_cell_dim * particles_per_cell_dim *
538 particles_per_cell_dim;
539
540 // Ensure correct space for the particles.
541 assert( positions.size() == static_cast<std::size_t>( particles_per_cell *
542 owned_cells.size() ) +
543 previous_num_particles );
544
545 // Initialize particles.
547 "Cabana::Grid::ParticleInit::Uniform", exec_space, owned_cells,
548 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
549 // Compute the owned local cell id.
550 int i_own = i - owned_cells.min( Dim::I );
551 int j_own = j - owned_cells.min( Dim::J );
552 int k_own = k - owned_cells.min( Dim::K );
553 int cell_id =
554 i_own + owned_cells.extent( Dim::I ) *
555 ( j_own + k_own * owned_cells.extent( Dim::J ) );
556
557 // Get the coordinates of the low cell node.
558 int low_node[3] = { i, j, k };
559 double low_coords[3];
560 local_mesh.coordinates( Node(), low_node, low_coords );
561
562 // Get the coordinates of the high cell node.
563 int high_node[3] = { i + 1, j + 1, k + 1 };
564 double high_coords[3];
565 local_mesh.coordinates( Node(), high_node, high_coords );
566
567 // Compute the particle spacing in each dimension.
568 double spacing[3] = { ( high_coords[Dim::I] - low_coords[Dim::I] ) /
569 particles_per_cell_dim,
570 ( high_coords[Dim::J] - low_coords[Dim::J] ) /
571 particles_per_cell_dim,
572 ( high_coords[Dim::K] - low_coords[Dim::K] ) /
573 particles_per_cell_dim };
574
575 // Create particles.
576 for ( int ip = 0; ip < particles_per_cell_dim; ++ip )
577 for ( int jp = 0; jp < particles_per_cell_dim; ++jp )
578 for ( int kp = 0; kp < particles_per_cell_dim; ++kp )
579 {
580 // Local particle id.
581 int pid = previous_num_particles +
582 cell_id * particles_per_cell + ip +
583 particles_per_cell_dim *
584 ( jp + particles_per_cell_dim * kp );
585
586 // Set the particle position in logical coordinates.
587 positions( pid, 0 ) = 0.5 * spacing[Dim::I] +
588 ip * spacing[Dim::I] +
589 low_coords[Dim::I];
590 positions( pid, 1 ) = 0.5 * spacing[Dim::J] +
591 jp * spacing[Dim::J] +
592 low_coords[Dim::J];
593 positions( pid, 2 ) = 0.5 * spacing[Dim::K] +
594 kp * spacing[Dim::K] +
595 low_coords[Dim::K];
596 }
597 } );
598}
599
600//---------------------------------------------------------------------------//
613template <class PositionType, class LocalGridType>
615 Cabana::InitUniform tag, PositionType& positions,
616 const int particles_per_cell_dim, LocalGridType& local_grid,
617 const std::size_t previous_num_particles = 0,
618 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
619 Kokkos::is_view<PositionType>::value ),
620 int>::type* = 0 )
621{
622 using exec_space = typename PositionType::execution_space;
623 createParticles( tag, exec_space{}, positions, particles_per_cell_dim,
624 local_grid, previous_num_particles );
625}
626} // namespace Grid
627} // namespace Cabana
628
629#endif
LocalMesh< MemorySpace, MeshType > createLocalMesh(const LocalGrid< MeshType > &local_grid)
Creation function for local mesh.
Definition Cabana_Grid_LocalMesh.hpp:779
Logical grid extension of Kokkos parallel iteration.
void grid_parallel_for(const std::string &label, const ExecutionSpace &exec_space, const IndexSpace< N > &index_space, const FunctorType &functor)
Execute a functor in parallel with a multidimensional execution policy specified by the given index s...
Definition Cabana_Grid_Parallel.hpp:52
int createParticles(Cabana::InitRandom, const ExecutionSpace &exec_space, const InitFunctor &create_functor, ParticleListType &particle_list, const int particles_per_cell, LocalGridType &local_grid, const std::size_t previous_num_particles=0, const bool shrink_to_fit=true, const uint64_t seed=123456, typename std::enable_if< is_particle_list< ParticleListType >::value, int >::type *=0)
Initialize a random number of particles in each cell given an initialization functor.
Definition Cabana_Grid_ParticleInit.hpp:68
Application-level particle/mesh storage and single particle access.
Particle creation utilities.
Slice a single particle property from an AoSoA.
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
Mesh cell tag.
Definition Cabana_Grid_Types.hpp:49
Local index tag.
Definition Cabana_Grid_Types.hpp:208
Mesh node tag.
Definition Cabana_Grid_Types.hpp:56
Owned decomposition tag.
Definition Cabana_Grid_Types.hpp:190
ParticleList static type checker.
Definition Cabana_Grid_ParticleList.hpp:119
Random particle initialization type tag.
Definition Cabana_ParticleInit.hpp:56
Uniform particle initialization type tag.
Definition Cabana_ParticleInit.hpp:52
Slice static type checker.
Definition Cabana_Slice.hpp:868