WarpX
Loading...
Searching...
No Matches
ShuffleFisherYates.H
Go to the documentation of this file.
1/* Copyright 2019 Yinjian Zhao
2 *
3 * This file is part of WarpX.
4 *
5 * License: BSD-3-Clause-LBNL
6 */
7#ifndef WARPX_PARTICLES_COLLISION_SHUFFLE_FISHER_YATES_H_
8#define WARPX_PARTICLES_COLLISION_SHUFFLE_FISHER_YATES_H_
9
10#include <AMReX_Random.H>
11#include <AMReX_Scan.H>
12
13/* \brief Shuffle array according to Fisher-Yates algorithm.
14 * Only shuffle the part between is <= i < ie, n = ie-is.
15 * T_index shall be
16 * amrex::DenseBins<WarpXParticleContainer::ParticleTileType::ParticleTileDataType>::index_type
17*/
18template <typename T_index>
20void ShuffleFisherYates (T_index *array, T_index const is, T_index const ie,
21 amrex::RandomEngine const& engine)
22{
23 T_index buf;
24 for (int i = ie-1; i >= static_cast<int>(is+1); --i)
25 {
26 // get random number j: is <= j <= i
27 const int j = amrex::Random_int(i-is+1, engine) + is;
28 // swap the ith array element with the jth
29 buf = array[i];
30 array[i] = array[j];
31 array[j] = buf;
32 }
33}
34
35/* \brief A helper class for computing and looping over the independent pairs of
36 macroparticles in each cell, for the purpose of processing collisions.
37 It also has the ability to shuffle the particles in each cell for both
38 species according to the Fisher-Yates algorithm.
39 The number of independent pairs is equivalent to the number of particles per cell in
40 whichever species has the fewer number of macroparticles.
41*/
42template <typename index_type>
44{
51
60 IndependentPairHelper (int a_n_cells,
61 index_type const* AMREX_RESTRICT a_cell_offsets_1,
62 index_type const* AMREX_RESTRICT a_cell_offsets_2)
63 : m_n_cells(a_n_cells), m_cell_offsets_1(a_cell_offsets_1), m_cell_offsets_2(a_cell_offsets_2)
64 {
66 m_coll_offsets.resize(m_n_cells+1);
67 Initialize();
68 }
69
70 /* \brief Compute the number of independent pairs in each cell. This is equal to
71 * the number of particles in whichever species has fewer
72 */
73 void Initialize () {
74 // Compute the number of independent pairs in each cell. This is equal to
75 // the number of particles in whichever species has fewer
76 index_type* AMREX_RESTRICT p_n_ind_pairs_in_each_cell = m_n_ind_pairs_in_each_cell.dataPtr();
77 int n_cells = m_n_cells;
78 index_type const* AMREX_RESTRICT cell_offsets_1 = m_cell_offsets_1;
79 index_type const* AMREX_RESTRICT cell_offsets_2 = m_cell_offsets_2;
80 amrex::ParallelFor( n_cells+1, [=] AMREX_GPU_DEVICE (int i_cell) noexcept
81 {
82 if (i_cell < n_cells)
83 {
84 const auto n_part_in_cell_1 = cell_offsets_1[i_cell+1] - cell_offsets_1[i_cell];
85 const auto n_part_in_cell_2 = cell_offsets_2[i_cell+1] - cell_offsets_2[i_cell];
86 p_n_ind_pairs_in_each_cell[i_cell] = amrex::min(n_part_in_cell_1, n_part_in_cell_2);
87 }
88 else
89 {
90 p_n_ind_pairs_in_each_cell[i_cell] = 0;
91 }
92 });
93
94 // number of total independent collision pairs
96 p_n_ind_pairs_in_each_cell, m_coll_offsets.data(), amrex::Scan::RetSum{true});
97 }
98
106 void shuffle (index_type* AMREX_RESTRICT a_indices_1,
107 index_type* AMREX_RESTRICT a_indices_2)
108 {
109 // shuffle each species.
110 // we launch 2*n_cells threads to process both species simultaneously
111 int n_cells = m_n_cells;
112 index_type const* AMREX_RESTRICT cell_offsets_1 = m_cell_offsets_1;
113 index_type const* AMREX_RESTRICT cell_offsets_2 = m_cell_offsets_2;
115 [=] AMREX_GPU_DEVICE (int i, amrex::RandomEngine const& engine) noexcept
116 {
117 int i_cell = i < n_cells ? i : i - n_cells;
118
119 // The particles from species1 that are in the cell `i_cell` are
120 // given by the `indices_1[cell_start_1:cell_stop_1]`
121 index_type const cell_start_1 = cell_offsets_1[i_cell];
122 index_type const cell_stop_1 = cell_offsets_1[i_cell+1];
123
124 // Same for species 2
125 index_type const cell_start_2 = cell_offsets_2[i_cell];
126 index_type const cell_stop_2 = cell_offsets_2[i_cell+1];
127
128 // Do not collide if one species is missing in the cell
129 if ( cell_stop_1 - cell_start_1 < 1 ||
130 cell_stop_2 - cell_start_2 < 1 ) { return; }
131
132 if (i < n_cells) {
133 ShuffleFisherYates(a_indices_1, cell_start_1, cell_stop_1, engine);
134 } else {
135 ShuffleFisherYates(a_indices_2, cell_start_2, cell_stop_2, engine);
136 }
137 });
138 }
139
141 const index_type* collisionOffsetsPtr () const {return m_coll_offsets.dataPtr();}
142};
143
144#endif // WARPX_PARTICLES_COLLISION_SHUFFLE_FISHER_YATES_H_
#define AMREX_RESTRICT
#define AMREX_INLINE
#define AMREX_GPU_DEVICE
#define AMREX_GPU_HOST_DEVICE
AMREX_GPU_HOST_DEVICE AMREX_INLINE void ShuffleFisherYates(T_index *array, T_index const is, T_index const ie, amrex::RandomEngine const &engine)
Definition ShuffleFisherYates.H:20
PODVector< T, ArenaAllocator< T > > DeviceVector
T ExclusiveSum(N n, T const *in, T *out, RetSum a_ret_sum=retSum)
std::enable_if_t< std::is_integral_v< T > > ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
unsigned int Random_int(unsigned int n)
__host__ __device__ constexpr const T & min(const T &a, const T &b) noexcept
AMREX_ATTRIBUTE_FLATTEN_FOR void ParallelForRNG(T n, L const &f) noexcept
amrex::Gpu::DeviceVector< index_type > m_coll_offsets
Definition ShuffleFisherYates.H:49
index_type const *AMREX_RESTRICT m_cell_offsets_2
Definition ShuffleFisherYates.H:47
void Initialize()
Definition ShuffleFisherYates.H:73
amrex::Gpu::DeviceVector< index_type > m_n_ind_pairs_in_each_cell
Definition ShuffleFisherYates.H:48
int m_n_cells
Definition ShuffleFisherYates.H:45
int numIndependentPairs() const
Definition ShuffleFisherYates.H:140
index_type const *AMREX_RESTRICT m_cell_offsets_1
Definition ShuffleFisherYates.H:46
void shuffle(index_type *AMREX_RESTRICT a_indices_1, index_type *AMREX_RESTRICT a_indices_2)
Shuffle the particles in each cell using the Fisher-Yates algorithm, for both species.
Definition ShuffleFisherYates.H:106
int m_n_independent_pairs
Definition ShuffleFisherYates.H:50
const index_type * collisionOffsetsPtr() const
Definition ShuffleFisherYates.H:141
IndependentPairHelper(int a_n_cells, index_type const *AMREX_RESTRICT a_cell_offsets_1, index_type const *AMREX_RESTRICT a_cell_offsets_2)
Constructor.
Definition ShuffleFisherYates.H:60