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<ExecutionSpace>( 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 =
91 global_grid.blockId() + ( seed % ( global_grid.blockId() + 1 ) );
92 using rnd_type = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
93 rnd_type pool;
94 pool.init( local_seed, owned_cells.size() );
95
96 // Get the aosoa.
97 auto& aosoa = particle_list.aosoa();
98
99 // Allocate enough space for the case the particles consume the entire
100 // local grid.
101 int num_particles = particles_per_cell * owned_cells.size();
102 aosoa.resize( previous_num_particles + num_particles );
103
104 // Creation count (start from previous).
105 auto count = Kokkos::View<int*, memory_space>( "particle_count", 1 );
106 Kokkos::deep_copy( count, previous_num_particles );
107
108 // Initialize particles.
110 "Cabana::Grid::ParticleInit::Random", exec_space, owned_cells,
111 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
112 // Compute the owned local cell id.
113 int i_own = i - owned_cells.min( Dim::I );
114 int j_own = j - owned_cells.min( Dim::J );
115 int k_own = k - owned_cells.min( Dim::K );
116 int cell_id =
117 i_own + owned_cells.extent( Dim::I ) *
118 ( j_own + k_own * owned_cells.extent( Dim::J ) );
119
120 // Get the coordinates of the low cell node.
121 int low_node[3] = { i, j, k };
122 double low_coords[3];
123 local_mesh.coordinates( Node(), low_node, low_coords );
124
125 // Get the coordinates of the high cell node.
126 int high_node[3] = { i + 1, j + 1, k + 1 };
127 double high_coords[3];
128 local_mesh.coordinates( Node(), high_node, high_coords );
129
130 // Random number generator.
131 auto rand = pool.get_state( cell_id );
132
133 // Particle coordinate.
134 double px[3];
135
136 // Particle volume.
137 double pv =
138 local_mesh.measure( Cell(), low_node ) / particles_per_cell;
139
140 // Create particles.
141 for ( int p = 0; p < particles_per_cell; ++p )
142 {
143 // Local particle id.
144 int pid =
145 previous_num_particles + cell_id * particles_per_cell + p;
146
147 // Select a random point in the cell for the particle
148 // location. These coordinates are logical.
149 for ( int d = 0; d < 3; ++d )
150 {
151 px[d] = Kokkos::rand<decltype( rand ), double>::draw(
152 rand, low_coords[d], high_coords[d] );
153 }
154
155 // Create a new particle with the given logical coordinates.
156 auto particle = particle_list.getParticle( pid );
157 bool created = create_functor( pid, px, pv, particle );
158
159 // If we created a new particle insert it into the list.
160 if ( created )
161 {
162 auto c = Kokkos::atomic_fetch_add( &count( 0 ), 1 );
163 particle_list.setParticle( particle, c );
164 }
165 }
166 } );
167 Kokkos::fence();
168
169 auto count_host =
170 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), count );
171 aosoa.resize( count_host( 0 ) );
172 if ( shrink_to_fit )
173 aosoa.shrinkToFit();
174 return count_host( 0 );
175}
176
196template <class InitFunctor, class ParticleListType, class LocalGridType>
198 Cabana::InitRandom tag, const InitFunctor& create_functor,
199 ParticleListType& particle_list, const int particles_per_cell,
200 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
201 const bool shrink_to_fit = true, const uint64_t seed = 123456,
202 typename std::enable_if<is_particle_list<ParticleListType>::value,
203 int>::type* = 0 )
204{
205 using exec_space = typename ParticleListType::memory_space::execution_space;
206 return createParticles( tag, exec_space{}, create_functor, particle_list,
207 particles_per_cell, local_grid,
208 previous_num_particles, shrink_to_fit, seed );
209}
210
211//---------------------------------------------------------------------------//
224template <class ExecutionSpace, class PositionType, class LocalGridType>
226 Cabana::InitRandom, const ExecutionSpace& exec_space,
227 PositionType& positions, const int particles_per_cell,
228 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
229 const uint64_t seed = 123456,
230 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
231 Kokkos::is_view<PositionType>::value ),
232 int>::type* = 0 )
233{
234 // Create a local mesh.
235 auto local_mesh = createLocalMesh<ExecutionSpace>( local_grid );
236
237 // Get the global grid.
238 const auto& global_grid = local_grid.globalGrid();
239
240 // Get the local set of owned cell indices.
241 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
242
243 // Create a random number generator.
244 const auto local_seed =
245 global_grid.blockId() + ( seed % ( global_grid.blockId() + 1 ) );
246 using rnd_type = Kokkos::Random_XorShift64_Pool<ExecutionSpace>;
247 rnd_type pool;
248 pool.init( local_seed, owned_cells.size() );
249
250 // Ensure correct space for the particles.
251 assert( positions.size() == static_cast<std::size_t>( particles_per_cell *
252 owned_cells.size() ) +
253 previous_num_particles );
254
255 // Initialize particles.
257 "Cabana::Grid::ParticleInit::Random", exec_space, owned_cells,
258 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
259 // Compute the owned local cell id.
260 int i_own = i - owned_cells.min( Dim::I );
261 int j_own = j - owned_cells.min( Dim::J );
262 int k_own = k - owned_cells.min( Dim::K );
263 int cell_id =
264 i_own + owned_cells.extent( Dim::I ) *
265 ( j_own + k_own * owned_cells.extent( Dim::J ) );
266
267 // Get the coordinates of the low cell node.
268 int low_node[3] = { i, j, k };
269 double low_coords[3];
270 local_mesh.coordinates( Node(), low_node, low_coords );
271
272 // Get the coordinates of the high cell node.
273 int high_node[3] = { i + 1, j + 1, k + 1 };
274 double high_coords[3];
275 local_mesh.coordinates( Node(), high_node, high_coords );
276
277 // Random number generator.
278 auto rand = pool.get_state( cell_id );
279
280 // Create particles.
281 for ( int p = 0; p < particles_per_cell; ++p )
282 {
283 // Local particle id.
284 int pid =
285 previous_num_particles + cell_id * particles_per_cell + p;
286
287 // Select a random point in the cell for the particle
288 // location. These coordinates are logical.
289 for ( int d = 0; d < 3; ++d )
290 {
291 positions( pid, d ) =
292 Kokkos::rand<decltype( rand ), double>::draw(
293 rand, low_coords[d], high_coords[d] );
294 }
295 }
296 } );
297}
298
311template <class PositionType, class LocalGridType>
313 Cabana::InitRandom tag, PositionType& positions,
314 const int particles_per_cell, LocalGridType& local_grid,
315 const std::size_t previous_num_particles = 0, const uint64_t seed = 123456,
316 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
317 Kokkos::is_view<PositionType>::value ),
318 int>::type* = 0 )
319{
320 using exec_space = typename PositionType::execution_space;
321 createParticles( tag, exec_space{}, positions, particles_per_cell,
322 local_grid, previous_num_particles, seed );
323}
324
325//---------------------------------------------------------------------------//
347template <class ExecutionSpace, class InitFunctor, class ParticleListType,
348 class LocalGridType>
350 Cabana::InitUniform, const ExecutionSpace& exec_space,
351 const InitFunctor& create_functor, ParticleListType& particle_list,
352 const int particles_per_cell_dim, LocalGridType& local_grid,
353 const std::size_t previous_num_particles = 0,
354 const bool shrink_to_fit = true,
355 typename std::enable_if<is_particle_list<ParticleListType>::value,
356 int>::type* = 0 )
357{
358 // Memory space.
359 using memory_space = typename ParticleListType::memory_space;
360
361 // Create a local mesh.
362 auto local_mesh = createLocalMesh<ExecutionSpace>( local_grid );
363
364 // Get the local set of owned cell indices.
365 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
366
367 // Get the aosoa.
368 auto& aosoa = particle_list.aosoa();
369
370 // Allocate enough space for particles fill the entire local grid.
371 int particles_per_cell = particles_per_cell_dim * particles_per_cell_dim *
372 particles_per_cell_dim;
373 int num_particles = particles_per_cell * owned_cells.size();
374 aosoa.resize( previous_num_particles + num_particles );
375
376 // Creation count (start from previous).
377 auto count = Kokkos::View<int*, memory_space>( "particle_count", 1 );
378 Kokkos::deep_copy( count, previous_num_particles );
379
380 // Initialize particles.
382 "Cabana::Grid::ParticleInit::Uniform", exec_space, owned_cells,
383 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
384 // Compute the owned local cell id.
385 int i_own = i - owned_cells.min( Dim::I );
386 int j_own = j - owned_cells.min( Dim::J );
387 int k_own = k - owned_cells.min( Dim::K );
388 int cell_id =
389 i_own + owned_cells.extent( Dim::I ) *
390 ( j_own + k_own * owned_cells.extent( Dim::J ) );
391
392 // Get the coordinates of the low cell node.
393 int low_node[3] = { i, j, k };
394 double low_coords[3];
395 local_mesh.coordinates( Node(), low_node, low_coords );
396
397 // Get the coordinates of the high cell node.
398 int high_node[3] = { i + 1, j + 1, k + 1 };
399 double high_coords[3];
400 local_mesh.coordinates( Node(), high_node, high_coords );
401
402 // Compute the particle spacing in each dimension.
403 double spacing[3] = { ( high_coords[Dim::I] - low_coords[Dim::I] ) /
404 particles_per_cell_dim,
405 ( high_coords[Dim::J] - low_coords[Dim::J] ) /
406 particles_per_cell_dim,
407 ( high_coords[Dim::K] - low_coords[Dim::K] ) /
408 particles_per_cell_dim };
409
410 // Particle coordinate.
411 double px[3];
412
413 // Particle volume.
414 double pv =
415 local_mesh.measure( Cell(), low_node ) / particles_per_cell;
416
417 // Create particles.
418 for ( int ip = 0; ip < particles_per_cell_dim; ++ip )
419 for ( int jp = 0; jp < particles_per_cell_dim; ++jp )
420 for ( int kp = 0; kp < particles_per_cell_dim; ++kp )
421 {
422 // Local particle id.
423 int pid = previous_num_particles +
424 cell_id * particles_per_cell + ip +
425 particles_per_cell_dim *
426 ( jp + particles_per_cell_dim * kp );
427
428 // Set the particle position in logical coordinates.
429 px[Dim::I] = 0.5 * spacing[Dim::I] +
430 ip * spacing[Dim::I] + low_coords[Dim::I];
431 px[Dim::J] = 0.5 * spacing[Dim::J] +
432 jp * spacing[Dim::J] + low_coords[Dim::J];
433 px[Dim::K] = 0.5 * spacing[Dim::K] +
434 kp * spacing[Dim::K] + low_coords[Dim::K];
435
436 // Create a new particle with the given logical
437 // coordinates.
438 auto particle = particle_list.getParticle( pid );
439 bool created = create_functor( pid, px, pv, particle );
440
441 // If we created a new particle insert it into the list.
442 if ( created )
443 {
444 // TODO: replace atomic with fill (use pid directly)
445 // and filter of empty list entries.
446 auto c = Kokkos::atomic_fetch_add( &count( 0 ), 1 );
447 particle_list.setParticle( particle, c );
448 }
449 }
450 } );
451 Kokkos::fence();
452
453 auto count_host =
454 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), count );
455 aosoa.resize( count_host( 0 ) );
456 if ( shrink_to_fit )
457 aosoa.shrinkToFit();
458 return count_host( 0 );
459}
460
480template <class InitFunctor, class ParticleListType, class LocalGridType>
482 Cabana::InitUniform tag, const InitFunctor& create_functor,
483 ParticleListType& particle_list, const int particles_per_cell_dim,
484 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
485 const bool shrink_to_fit = true,
486 typename std::enable_if<is_particle_list<ParticleListType>::value,
487 int>::type* = 0 )
488{
489 using exec_space = typename ParticleListType::memory_space::execution_space;
490 return createParticles( tag, exec_space{}, create_functor, particle_list,
491 particles_per_cell_dim, local_grid,
492 previous_num_particles, shrink_to_fit );
493}
494
495//---------------------------------------------------------------------------//
508template <class ExecutionSpace, class PositionType, class LocalGridType>
510 Cabana::InitUniform, const ExecutionSpace& exec_space,
511 PositionType& positions, const int particles_per_cell_dim,
512 LocalGridType& local_grid, const std::size_t previous_num_particles = 0,
513 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
514 Kokkos::is_view<PositionType>::value ),
515 int>::type* = 0 )
516{
517 // Create a local mesh.
518 auto local_mesh = createLocalMesh<ExecutionSpace>( local_grid );
519
520 // Get the local set of owned cell indices.
521 auto owned_cells = local_grid.indexSpace( Own(), Cell(), Local() );
522
523 int particles_per_cell = particles_per_cell_dim * particles_per_cell_dim *
524 particles_per_cell_dim;
525
526 // Ensure correct space for the particles.
527 assert( positions.size() == static_cast<std::size_t>( particles_per_cell *
528 owned_cells.size() ) +
529 previous_num_particles );
530
531 // Initialize particles.
533 "Cabana::Grid::ParticleInit::Uniform", exec_space, owned_cells,
534 KOKKOS_LAMBDA( const int i, const int j, const int k ) {
535 // Compute the owned local cell id.
536 int i_own = i - owned_cells.min( Dim::I );
537 int j_own = j - owned_cells.min( Dim::J );
538 int k_own = k - owned_cells.min( Dim::K );
539 int cell_id =
540 i_own + owned_cells.extent( Dim::I ) *
541 ( j_own + k_own * owned_cells.extent( Dim::J ) );
542
543 // Get the coordinates of the low cell node.
544 int low_node[3] = { i, j, k };
545 double low_coords[3];
546 local_mesh.coordinates( Node(), low_node, low_coords );
547
548 // Get the coordinates of the high cell node.
549 int high_node[3] = { i + 1, j + 1, k + 1 };
550 double high_coords[3];
551 local_mesh.coordinates( Node(), high_node, high_coords );
552
553 // Compute the particle spacing in each dimension.
554 double spacing[3] = { ( high_coords[Dim::I] - low_coords[Dim::I] ) /
555 particles_per_cell_dim,
556 ( high_coords[Dim::J] - low_coords[Dim::J] ) /
557 particles_per_cell_dim,
558 ( high_coords[Dim::K] - low_coords[Dim::K] ) /
559 particles_per_cell_dim };
560
561 // Create particles.
562 for ( int ip = 0; ip < particles_per_cell_dim; ++ip )
563 for ( int jp = 0; jp < particles_per_cell_dim; ++jp )
564 for ( int kp = 0; kp < particles_per_cell_dim; ++kp )
565 {
566 // Local particle id.
567 int pid = previous_num_particles +
568 cell_id * particles_per_cell + ip +
569 particles_per_cell_dim *
570 ( jp + particles_per_cell_dim * kp );
571
572 // Set the particle position in logical coordinates.
573 positions( pid, 0 ) = 0.5 * spacing[Dim::I] +
574 ip * spacing[Dim::I] +
575 low_coords[Dim::I];
576 positions( pid, 1 ) = 0.5 * spacing[Dim::J] +
577 jp * spacing[Dim::J] +
578 low_coords[Dim::J];
579 positions( pid, 2 ) = 0.5 * spacing[Dim::K] +
580 kp * spacing[Dim::K] +
581 low_coords[Dim::K];
582 }
583 } );
584}
585
586//---------------------------------------------------------------------------//
599template <class PositionType, class LocalGridType>
601 Cabana::InitUniform tag, PositionType& positions,
602 const int particles_per_cell_dim, LocalGridType& local_grid,
603 const std::size_t previous_num_particles = 0,
604 typename std::enable_if<( Cabana::is_slice<PositionType>::value ||
605 Kokkos::is_view<PositionType>::value ),
606 int>::type* = 0 )
607{
608 using exec_space = typename PositionType::execution_space;
609 createParticles( tag, exec_space{}, positions, particles_per_cell_dim,
610 local_grid, previous_num_particles );
611}
612} // namespace Grid
613} // namespace Cabana
614
615#endif
LocalMesh< MemorySpace, MeshType > createLocalMesh(const LocalGrid< MeshType > &local_grid)
Creation function for local mesh.
Definition Cabana_Grid_LocalMesh.hpp:791
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:861