WarpX
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 WARPX_PARTICLE_CREATION_FUNC_H_
9 #define WARPX_PARTICLE_CREATION_FUNC_H_
10 
11 #include "BinaryCollisionUtils.H"
12 
18 
19 #include <AMReX_DenseBins.H>
20 #include <AMReX_GpuAtomic.H>
21 #include <AMReX_GpuDevice.H>
22 #include <AMReX_GpuContainers.H>
23 #include <AMReX_INT.H>
24 #include <AMReX_Random.H>
25 #include <AMReX_REAL.H>
26 #include <AMReX_Vector.H>
27 
33 {
34  // Define shortcuts for frequently-used type names
41 
42 public:
46  ParticleCreationFunc () = default;
47 
54  ParticleCreationFunc (const std::string& collision_name, MultiParticleContainer const * mypc);
55 
95  const index_type& n_total_pairs,
96  ParticleTileType& ptile1, ParticleTileType& ptile2,
97  const amrex::Vector<WarpXParticleContainer*>& pc_products,
98  ParticleTileType** AMREX_RESTRICT tile_products,
99  const amrex::ParticleReal& m1, const amrex::ParticleReal& m2,
100  const amrex::Vector<amrex::ParticleReal>& products_mass,
101  const index_type* AMREX_RESTRICT p_mask,
102  const amrex::Vector<index_type>& products_np,
103  const SmartCopy* AMREX_RESTRICT copy_species1,
104  const SmartCopy* AMREX_RESTRICT copy_species2,
105  const index_type* AMREX_RESTRICT p_pair_indices_1,
106  const index_type* AMREX_RESTRICT p_pair_indices_2,
107  const amrex::ParticleReal* AMREX_RESTRICT p_pair_reaction_weight
108  ) const
109  {
110  using namespace amrex::literals;
111 
112  if (n_total_pairs == 0) { return amrex::Vector<int>(m_num_product_species, 0); }
113 
114  // Compute offset array and allocate memory for the produced species
115  amrex::Gpu::DeviceVector<index_type> offsets(n_total_pairs);
116  const auto total = amrex::Scan::ExclusiveSum(n_total_pairs, p_mask, offsets.data());
117  const index_type* AMREX_RESTRICT p_offsets = offsets.dataPtr();
119  for (int i = 0; i < m_num_product_species; i++)
120  {
121  // How many particles of product species i are created.
122  // Factor 2 is here because we currently create one product species at the position of
123  // each source particle of the binary collision. E.g., if a binary collision produces
124  // one electron, we create two electrons, one at the position of each particle that
125  // collided. This allows for exact charge conservation.
126  const index_type num_added = total * m_num_products_host[i] * 2;
127  num_added_vec[i] = static_cast<int>(num_added);
128  tile_products[i]->resize(products_np[i] + num_added);
129  }
130 
131  const auto soa_1 = ptile1.getParticleTileData();
132  const auto soa_2 = ptile2.getParticleTileData();
133 
134  amrex::ParticleReal* AMREX_RESTRICT w1 = soa_1.m_rdata[PIdx::w];
135  amrex::ParticleReal* AMREX_RESTRICT w2 = soa_2.m_rdata[PIdx::w];
136  uint64_t* AMREX_RESTRICT idcpu1 = soa_1.m_idcpu;
137  uint64_t* AMREX_RESTRICT idcpu2 = soa_2.m_idcpu;
138 
139  // Create necessary GPU vectors, that will be used in the kernel below
140  amrex::Vector<SoaData_type> soa_products;
141  for (int i = 0; i < m_num_product_species; i++)
142  {
143  soa_products.push_back(tile_products[i]->getParticleTileData());
144  }
145 #ifdef AMREX_USE_GPU
149  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, soa_products.begin(),
150  soa_products.end(),
151  device_soa_products.begin());
152  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_np.begin(),
153  products_np.end(),
154  device_products_np.begin());
155  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_mass.begin(),
156  products_mass.end(),
157  device_products_mass.begin());
159  SoaData_type* AMREX_RESTRICT soa_products_data = device_soa_products.data();
160  const index_type* AMREX_RESTRICT products_np_data = device_products_np.data();
161  const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = device_products_mass.data();
162 #else
163  SoaData_type* AMREX_RESTRICT soa_products_data = soa_products.data();
164  const index_type* AMREX_RESTRICT products_np_data = products_np.data();
165  const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = products_mass.data();
166 #endif
167 
168  const int t_num_product_species = m_num_product_species;
169  const int* AMREX_RESTRICT p_num_products_device = m_num_products_device.data();
170  const CollisionType t_collision_type = m_collision_type;
171 
172  amrex::ParallelForRNG(n_total_pairs,
173  [=] AMREX_GPU_DEVICE (int i, amrex::RandomEngine const& engine) noexcept
174  {
175  if (p_mask[i])
176  {
177  for (int j = 0; j < t_num_product_species; j++)
178  {
179  for (int k = 0; k < p_num_products_device[j]; k++)
180  {
181  // Factor 2 is here because we create one product species at the position
182  // of each source particle
183  const auto product_index = products_np_data[j] +
184  2*(p_offsets[i]*p_num_products_device[j] + k);
185  // Create product particle at position of particle 1
186  copy_species1[j](soa_products_data[j], soa_1, static_cast<int>(p_pair_indices_1[i]),
187  static_cast<int>(product_index), engine);
188  // Create another product particle at position of particle 2
189  copy_species2[j](soa_products_data[j], soa_2, static_cast<int>(p_pair_indices_2[i]),
190  static_cast<int>(product_index + 1), engine);
191 
192  // Set the weight of the new particles to p_pair_reaction_weight[i]/2
193  soa_products_data[j].m_rdata[PIdx::w][product_index] =
194  p_pair_reaction_weight[i]/amrex::ParticleReal(2.);
195  soa_products_data[j].m_rdata[PIdx::w][product_index + 1] =
196  p_pair_reaction_weight[i]/amrex::ParticleReal(2.);
197  }
198  }
199 
200  // Remove p_pair_reaction_weight[i] from the colliding particles' weights
202  w1[p_pair_indices_1[i]], idcpu1[p_pair_indices_1[i]], p_pair_reaction_weight[i]);
204  w2[p_pair_indices_2[i]], idcpu2[p_pair_indices_2[i]], p_pair_reaction_weight[i]);
205 
206  // Initialize the product particles' momentum, using a function depending on the
207  // specific collision type
208  if (t_collision_type == CollisionType::ProtonBoronToAlphasFusion)
209  {
210  const index_type product_start_index = products_np_data[0] + 2*p_offsets[i]*
211  p_num_products_device[0];
212  ProtonBoronFusionInitializeMomentum(soa_1, soa_2, soa_products_data[0],
213  p_pair_indices_1[i], p_pair_indices_2[i],
214  product_start_index, m1, m2, engine);
215  }
216  else if ((t_collision_type == CollisionType::DeuteriumTritiumToNeutronHeliumFusion)
219  {
220  amrex::ParticleReal fusion_energy = 0.0_prt;
222  fusion_energy = 17.5893e6_prt * PhysConst::q_e;
223  }
224  else if (t_collision_type == CollisionType::DeuteriumDeuteriumToProtonTritiumFusion) {
225  fusion_energy = 4.032667e6_prt * PhysConst::q_e;
226  }
227  else if (t_collision_type == CollisionType::DeuteriumDeuteriumToNeutronHeliumFusion) {
228  fusion_energy = 3.268911e6_prt * PhysConst::q_e;
229  }
230  TwoProductFusionInitializeMomentum(soa_1, soa_2,
231  soa_products_data[0], soa_products_data[1],
232  p_pair_indices_1[i], p_pair_indices_2[i],
233  products_np_data[0] + 2*p_offsets[i]*p_num_products_device[0],
234  products_np_data[1] + 2*p_offsets[i]*p_num_products_device[1],
235  m1, m2, products_mass_data[0], products_mass_data[1], fusion_energy, engine);
236  }
237 
238  }
239  });
240 
241  // Initialize the user runtime components
242  for (int i = 0; i < m_num_product_species; i++)
243  {
244  const auto start_index = int(products_np[i]);
245  const auto stop_index = int(products_np[i] + num_added_vec[i]);
247  0, 0,
248  pc_products[i]->getUserRealAttribs(), pc_products[i]->getUserIntAttribs(),
249  pc_products[i]->getParticleComps(), pc_products[i]->getParticleiComps(),
250  pc_products[i]->getUserRealAttribParser(),
251  pc_products[i]->getUserIntAttribParser(),
252 #ifdef WARPX_QED
253  false, // do not initialize QED quantities, since they were initialized
254  // when calling the SmartCopy functors
255  pc_products[i]->get_breit_wheeler_engine_ptr(),
256  pc_products[i]->get_quantum_sync_engine_ptr(),
257 #endif
258  pc_products[i]->getIonizationInitialLevel(),
259  start_index, stop_index);
260  }
261 
263 
264  return num_added_vec;
265  }
266 
267 private:
268  // How many different type of species the collision produces
270  // Vectors of size m_num_product_species storing how many particles of a given species are
271  // produced by a collision event. These vectors are duplicated (one version for host and one
272  // for device) which is necessary with GPUs but redundant on CPU.
276 };
277 
278 
284 {
291 
292 public:
294 
295  NoParticleCreationFunc (const std::string& /*collision_name*/,
296  MultiParticleContainer const * const /*mypc*/) {}
297 
300  const index_type& /*n_total_pairs*/,
301  ParticleTileType& /*ptile1*/, ParticleTileType& /*ptile2*/,
303  ParticleTileType** /*tile_products*/,
304  const amrex::ParticleReal& /*m1*/, const amrex::ParticleReal& /*m2*/,
305  const amrex::Vector<amrex::ParticleReal>& /*products_mass*/,
306  const index_type* /*p_mask*/, const amrex::Vector<index_type>& /*products_np*/,
307  const SmartCopy* /*copy_species1*/, const SmartCopy* /*copy_species2*/,
308  const index_type* /*p_pair_indices_1*/, const index_type* /*p_pair_indices_2*/,
309  const amrex::ParticleReal* /*p_pair_reaction_weight*/
310  ) const
311  {
312  return {};
313  }
314 };
315 
316 #endif // WARPX_PARTICLE_CREATION_FUNC_H_
#define AMREX_RESTRICT
#define AMREX_INLINE
#define AMREX_GPU_DEVICE
CollisionType
Definition: BinaryCollisionUtils.H:17
@ ProtonBoronToAlphasFusion
@ DeuteriumDeuteriumToProtonTritiumFusion
@ DeuteriumDeuteriumToNeutronHeliumFusion
@ DeuteriumTritiumToNeutronHeliumFusion
Definition: MultiParticleContainer.H:66
This class does nothing and is used as second template parameter for binary collisions that do not cr...
Definition: ParticleCreationFunc.H:284
typename WarpXParticleContainer::ParticleType ParticleType
Definition: ParticleCreationFunc.H:285
NoParticleCreationFunc(const std::string &, MultiParticleContainer const *const)
Definition: ParticleCreationFunc.H:295
typename ParticleBins::index_type index_type
Definition: ParticleCreationFunc.H:289
NoParticleCreationFunc()=default
typename WarpXParticleContainer::ParticleTileType ParticleTileType
Definition: ParticleCreationFunc.H:286
typename ParticleTileType::ParticleTileDataType ParticleTileDataType
Definition: ParticleCreationFunc.H:287
typename WarpXParticleContainer::ParticleTileType::ParticleTileDataType SoaData_type
Definition: ParticleCreationFunc.H:290
This functor creates particles produced from a binary collision and sets their initial properties (po...
Definition: ParticleCreationFunc.H:33
CollisionType m_collision_type
Definition: ParticleCreationFunc.H:275
AMREX_INLINE amrex::Vector< int > operator()(const index_type &n_total_pairs, ParticleTileType &ptile1, ParticleTileType &ptile2, const amrex::Vector< WarpXParticleContainer * > &pc_products, ParticleTileType **AMREX_RESTRICT tile_products, 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:94
int m_num_product_species
Definition: ParticleCreationFunc.H:269
amrex::Gpu::DeviceVector< int > m_num_products_device
Definition: ParticleCreationFunc.H:273
typename ParticleTileType::ParticleTileDataType ParticleTileDataType
Definition: ParticleCreationFunc.H:37
typename WarpXParticleContainer::ParticleType ParticleType
Definition: ParticleCreationFunc.H:35
typename ParticleBins::index_type index_type
Definition: ParticleCreationFunc.H:39
typename WarpXParticleContainer::ParticleTileType ParticleTileType
Definition: ParticleCreationFunc.H:36
ParticleCreationFunc()=default
Default constructor of the ParticleCreationFunc class.
typename WarpXParticleContainer::ParticleTileType::ParticleTileDataType SoaData_type
Definition: ParticleCreationFunc.H:40
amrex::Gpu::HostVector< int > m_num_products_host
Definition: ParticleCreationFunc.H:274
unsigned int index_type
T * data() noexcept
iterator begin() noexcept
T * dataPtr() noexcept
ParticleTile< ParticleType, NArrayReal, NArrayInt, Allocator > ParticleTileType
AMREX_GPU_HOST_DEVICE AMREX_INLINE void remove_weight_from_colliding_particle(amrex::ParticleReal &weight, uint64_t &idcpu, const amrex::ParticleReal reaction_weight)
Subtract given weight from particle and set its ID to invalid if the weight reaches zero.
Definition: BinaryCollisionUtils.H:135
void DefaultInitializeRuntimeAttributes(PTile &ptile, const int n_external_attr_real, const int n_external_attr_int, const std::vector< std::string > &user_real_attribs, const std::vector< std::string > &user_int_attribs, const std::map< std::string, int > &particle_comps, const std::map< std::string, int > &particle_icomps, const std::vector< amrex::Parser * > &user_real_attrib_parser, const std::vector< amrex::Parser * > &user_int_attrib_parser, const bool do_qed_comps, BreitWheelerEngine *p_bw_engine, QuantumSynchrotronEngine *p_qs_engine, const int ionization_initial_level, int start, int stop)
Default initialize runtime attributes in a tile. This routine does not initialize the first n_externa...
Definition: DefaultInitialization.H:118
typename ParticleTileType::ParticleTileDataType ParticleTileDataType
Definition: ParticleUtils.cpp:33
static constexpr auto q_e
elementary charge [C]
Definition: constant.H:50
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)
const int[]
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:33
This is a functor for performing a "smart copy" that works in both host and device code.
Definition: SmartCopy.H:34
ParticleTileData< StorageParticleType, NArrayReal, NArrayInt > ParticleTileDataType