ARTEMIS
ParticleCreationFunc.H
Go to the documentation of this file.
1 /* Copyright 2021 Neil Zaim
2  *
3  * This file is part of WarpX.
4  *
5  * License: BSD-3-Clause-LBNL
6  */
7 
8 #ifndef PARTICLE_CREATION_FUNC_H_
9 #define PARTICLE_CREATION_FUNC_H_
10 
11 #include "BinaryCollisionUtils.H"
12 
18 #include "WarpX.H"
19 
20 #include <AMReX_DenseBins.H>
21 #include <AMReX_GpuAtomic.H>
22 #include <AMReX_GpuDevice.H>
23 #include <AMReX_GpuContainers.H>
24 #include <AMReX_INT.H>
25 #include <AMReX_Random.H>
26 #include <AMReX_REAL.H>
27 #include <AMReX_Vector.H>
28 
34  // Define shortcuts for frequently-used type names
40 
41 public:
45  ParticleCreationFunc () = default;
46 
53  ParticleCreationFunc (const std::string collision_name, MultiParticleContainer const * const mypc);
54 
101  const index_type& n_total_pairs,
102  const SoaData_type soa_1, const SoaData_type soa_2,
103  ParticleTileType** AMREX_RESTRICT tile_products,
104  ParticleType* particle_ptr_1, ParticleType* particle_ptr_2,
105  const amrex::ParticleReal& m1, const amrex::ParticleReal& m2,
106  const amrex::Vector<amrex::ParticleReal>& products_mass,
107  const index_type* AMREX_RESTRICT p_mask,
108  const amrex::Vector<index_type>& products_np,
109  const SmartCopy* AMREX_RESTRICT copy_species1,
110  const SmartCopy* AMREX_RESTRICT copy_species2,
111  const index_type* AMREX_RESTRICT p_pair_indices_1,
112  const index_type* AMREX_RESTRICT p_pair_indices_2,
113  const amrex::ParticleReal* AMREX_RESTRICT p_pair_reaction_weight
114  ) const
115  {
116  if (n_total_pairs == 0) return amrex::Vector<int>(m_num_product_species, 0);
117 
118  // Compute offset array and allocate memory for the produced species
119  amrex::Gpu::DeviceVector<index_type> offsets(n_total_pairs);
120  const auto total = amrex::Scan::ExclusiveSum(n_total_pairs, p_mask, offsets.data());
121  const index_type* AMREX_RESTRICT p_offsets = offsets.dataPtr();
123  for (int i = 0; i < m_num_product_species; i++)
124  {
125  // How many particles of product species i are created.
126  // Factor 2 is here because we currently create one product species at the position of
127  // each source particle of the binary collision. E.g., if a binary collision produces
128  // one electron, we create two electrons, one at the position of each particle that
129  // collided. This allows for exact charge conservation.
130  const index_type num_added = total * m_num_products_host[i] * 2;
131  num_added_vec[i] = num_added;
132  tile_products[i]->resize(products_np[i] + num_added);
133  }
134 
135  amrex::ParticleReal* AMREX_RESTRICT w1 = soa_1.m_rdata[PIdx::w];
136  amrex::ParticleReal* AMREX_RESTRICT w2 = soa_2.m_rdata[PIdx::w];
137 
138  // Create necessary GPU vectors, that will be used in the kernel below
139  amrex::Vector<SoaData_type> soa_products;
140  for (int i = 0; i < m_num_product_species; i++)
141  {
142  soa_products.push_back(tile_products[i]->getParticleTileData());
143  }
144 #ifdef AMREX_USE_GPU
148  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, soa_products.begin(),
149  soa_products.end(),
150  device_soa_products.begin());
151  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_np.begin(),
152  products_np.end(),
153  device_products_np.begin());
154  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_mass.begin(),
155  products_mass.end(),
156  device_products_mass.begin());
158  SoaData_type* AMREX_RESTRICT soa_products_data = device_soa_products.data();
159  const index_type* AMREX_RESTRICT products_np_data = device_products_np.data();
160  const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = device_products_mass.data();
161 #else
162  SoaData_type* AMREX_RESTRICT soa_products_data = soa_products.data();
163  const index_type* AMREX_RESTRICT products_np_data = products_np.data();
164  const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = products_mass.data();
165 #endif
166 
167  const int t_num_product_species = m_num_product_species;
168  const int* AMREX_RESTRICT p_num_products_device = m_num_products_device.data();
169  const CollisionType t_collision_type = m_collision_type;
170 
171  amrex::ParallelForRNG(n_total_pairs,
172  [=] AMREX_GPU_DEVICE (int i, amrex::RandomEngine const& engine) noexcept
173  {
174  if (p_mask[i])
175  {
176  for (int j = 0; j < t_num_product_species; j++)
177  {
178  for (int k = 0; k < p_num_products_device[j]; k++)
179  {
180  // Factor 2 is here because we create one product species at the position
181  // of each source particle
182  const auto product_index = products_np_data[j] +
183  2*(p_offsets[i]*p_num_products_device[j] + k);
184  // Create product particle at position of particle 1
185  copy_species1[j](soa_products_data[j], soa_1, p_pair_indices_1[i],
186  product_index, engine);
187  // Create another product particle at position of particle 2
188  copy_species2[j](soa_products_data[j], soa_2, p_pair_indices_2[i],
189  product_index + 1, engine);
190 
191  // Set the weight of the new particles to p_pair_reaction_weight[i]/2
192  soa_products_data[j].m_rdata[PIdx::w][product_index] =
193  p_pair_reaction_weight[i]/amrex::ParticleReal(2.);
194  soa_products_data[j].m_rdata[PIdx::w][product_index + 1] =
195  p_pair_reaction_weight[i]/amrex::ParticleReal(2.);
196  }
197  }
198 
199  // Remove p_pair_reaction_weight[i] from the colliding particles' weights
200  amrex::Gpu::Atomic::AddNoRet(&w1[p_pair_indices_1[i]],
201  -p_pair_reaction_weight[i]);
202  amrex::Gpu::Atomic::AddNoRet(&w2[p_pair_indices_2[i]],
203  -p_pair_reaction_weight[i]);
204 
205  // If the colliding particle weight decreases to zero, remove particle by
206  // setting its id to -1
207  constexpr amrex::Long minus_one_long = -1;
208  if (w1[p_pair_indices_1[i]] <= amrex::ParticleReal(0.))
209  {
210  particle_ptr_1[p_pair_indices_1[i]].atomicSetID(minus_one_long);
211  }
212  if (w2[p_pair_indices_2[i]] <= amrex::ParticleReal(0.))
213  {
214  particle_ptr_2[p_pair_indices_2[i]].atomicSetID(minus_one_long);
215  }
216 
217  // Initialize the product particles' momentum, using a function depending on the
218  // specific collision type
219  if (t_collision_type == CollisionType::ProtonBoronToAlphasFusion)
220  {
221  const index_type product_start_index = products_np_data[0] + 2*p_offsets[i]*
222  p_num_products_device[0];
223  ProtonBoronFusionInitializeMomentum(soa_1, soa_2, soa_products_data[0],
224  p_pair_indices_1[i], p_pair_indices_2[i],
225  product_start_index, m1, m2, engine);
226  }
227  else if ((t_collision_type == CollisionType::DeuteriumTritiumToNeutronHeliumFusion)
230  {
231  amrex::ParticleReal fusion_energy = 0.0_prt;
233  fusion_energy = 17.5893e6_prt * PhysConst::q_e;
234  }
235  else if (t_collision_type == CollisionType::DeuteriumDeuteriumToProtonTritiumFusion) {
236  fusion_energy = 4.032667e6_prt * PhysConst::q_e;
237  }
238  else if (t_collision_type == CollisionType::DeuteriumDeuteriumToNeutronHeliumFusion) {
239  fusion_energy = 3.268911e6_prt * PhysConst::q_e;
240  }
241  TwoProductFusionInitializeMomentum(soa_1, soa_2,
242  soa_products_data[0], soa_products_data[1],
243  p_pair_indices_1[i], p_pair_indices_2[i],
244  products_np_data[0] + 2*p_offsets[i]*p_num_products_device[0],
245  products_np_data[1] + 2*p_offsets[i]*p_num_products_device[1],
246  m1, m2, products_mass_data[0], products_mass_data[1], fusion_energy, engine);
247  }
248 
249  }
250  });
251 
253 
254  return num_added_vec;
255  }
256 
257 private:
258  // How many different type of species the collision produces
260  // Vectors of size m_num_product_species storing how many particles of a given species are
261  // produced by a collision event. These vectors are duplicated (one version for host and one
262  // for device) which is necessary with GPUs but redundant on CPU.
266 };
267 
268 
279 
280 public:
282 
283  NoParticleCreationFunc (const std::string /*collision_name*/,
284  MultiParticleContainer const * const /*mypc*/) {}
285 
288  const index_type& /*n_total_pairs*/,
289  const SoaData_type /*soa_1*/, const SoaData_type /*soa_2*/,
290  ParticleTileType** /*tile_products*/,
291  ParticleType* /*particle_ptr_1*/, ParticleType* /*particle_ptr_2*/,
292  const amrex::ParticleReal& /*m1*/, const amrex::ParticleReal& /*m2*/,
293  const amrex::Vector<amrex::ParticleReal>& /*products_mass*/,
294  const index_type* /*p_mask*/, const amrex::Vector<index_type>& /*products_np*/,
295  const SmartCopy* /*copy_species1*/, const SmartCopy* /*copy_species2*/,
296  const index_type* /*p_pair_indices_1*/, const index_type* /*p_pair_indices_2*/,
297  const amrex::ParticleReal* /*p_pair_reaction_weight*/
298  ) const
299  {
300  return amrex::Vector<int>();
301  }
302 };
303 
304 #endif // PARTICLE_CREATION_FUNC_H_
#define AMREX_RESTRICT
#define AMREX_INLINE
#define AMREX_GPU_DEVICE
CollisionType
Definition: BinaryCollisionUtils.H:15
@ ProtonBoronToAlphasFusion
@ DeuteriumDeuteriumToProtonTritiumFusion
@ DeuteriumDeuteriumToNeutronHeliumFusion
@ DeuteriumTritiumToNeutronHeliumFusion
Definition: MultiParticleContainer.H:65
This class does nothing and is used as second template parameter for binary collisions that do not cr...
Definition: ParticleCreationFunc.H:273
NoParticleCreationFunc(const std::string, MultiParticleContainer const *const)
Definition: ParticleCreationFunc.H:283
WarpXParticleContainer::ParticleType ParticleType
Definition: ParticleCreationFunc.H:274
NoParticleCreationFunc()=default
ParticleBins::index_type index_type
Definition: ParticleCreationFunc.H:277
AMREX_INLINE amrex::Vector< int > operator()(const index_type &, const SoaData_type, const SoaData_type, ParticleTileType **, ParticleType *, ParticleType *, const amrex::ParticleReal &, const amrex::ParticleReal &, const amrex::Vector< amrex::ParticleReal > &, const index_type *, const amrex::Vector< index_type > &, const SmartCopy *, const SmartCopy *, const index_type *, const index_type *, const amrex::ParticleReal *) const
Definition: ParticleCreationFunc.H:287
This functor creates particles produced from a binary collision and sets their initial properties (po...
Definition: ParticleCreationFunc.H:33
WarpXParticleContainer::ParticleType ParticleType
Definition: ParticleCreationFunc.H:35
CollisionType m_collision_type
Definition: ParticleCreationFunc.H:265
ParticleBins::index_type index_type
Definition: ParticleCreationFunc.H:38
int m_num_product_species
Definition: ParticleCreationFunc.H:259
amrex::Gpu::DeviceVector< int > m_num_products_device
Definition: ParticleCreationFunc.H:263
AMREX_INLINE amrex::Vector< int > operator()(const index_type &n_total_pairs, const SoaData_type soa_1, const SoaData_type soa_2, ParticleTileType **AMREX_RESTRICT tile_products, ParticleType *particle_ptr_1, ParticleType *particle_ptr_2, const amrex::ParticleReal &m1, const amrex::ParticleReal &m2, const amrex::Vector< amrex::ParticleReal > &products_mass, const index_type *AMREX_RESTRICT p_mask, const amrex::Vector< index_type > &products_np, const SmartCopy *AMREX_RESTRICT copy_species1, const SmartCopy *AMREX_RESTRICT copy_species2, const index_type *AMREX_RESTRICT p_pair_indices_1, const index_type *AMREX_RESTRICT p_pair_indices_2, const amrex::ParticleReal *AMREX_RESTRICT p_pair_reaction_weight) const
operator() of the ParticleCreationFunc class. It creates new particles from binary collisions....
Definition: ParticleCreationFunc.H:100
ParticleCreationFunc()=default
Default constructor of the ParticleCreationFunc class.
amrex::Gpu::HostVector< int > m_num_products_host
Definition: ParticleCreationFunc.H:264
iterator begin() noexcept
T * dataPtr() noexcept
T * data() noexcept
ParticleTile< ParticleType, NArrayReal, NArrayInt, Allocator > ParticleTileType
static constexpr auto q_e
elementary charge [C]
Definition: constant.H:50
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
void synchronize() noexcept
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr HostToDevice hostToDevice
void streamSynchronize() noexcept
T ExclusiveSum(N n, T const *in, T *out, RetSum a_ret_sum=retSum)
AMREX_ATTRIBUTE_FLATTEN_FOR void ParallelForRNG(T n, L const &f) noexcept
i
Definition: check_interp_points_and_weights.py:174
@ w
weight
Definition: NamedComponentParticleContainer.H:24
This is a functor for performing a "smart copy" that works in both host and device code.
Definition: SmartCopy.H:34
GpuArray< ParticleReal *, NAR > m_rdata
ParticleTileData< StorageParticleType, NArrayReal, NArrayInt > ParticleTileDataType