WarpX
SplitAndScatterFunc.H
Go to the documentation of this file.
1 /* Copyright 2023 The WarpX Community
2  *
3  * This file is part of WarpX.
4  *
5  * Authors: Roelof Groenewald (TAE Technologies)
6  *
7  * License: BSD-3-Clause-LBNL
8  */
9 #ifndef SPLIT_AND_SCATTER_FUNC_H_
10 #define SPLIT_AND_SCATTER_FUNC_H_
11 
13 
20 template <typename index_type, typename Tile, typename Index, typename CopyFunc,
23  const index_type& n_total_pairs,
24  Tile& ptile1, Tile& ptile2,
25  const Index* AMREX_RESTRICT mask,
26  CopyFunc&& copy1, CopyFunc&& copy2,
27  const amrex::ParticleReal m1, const amrex::ParticleReal m2,
28  const index_type* AMREX_RESTRICT p_pair_indices_1,
29  const index_type* AMREX_RESTRICT p_pair_indices_2,
30  const amrex::ParticleReal* AMREX_RESTRICT p_pair_reaction_weight ) noexcept
31 {
32  using namespace amrex;
33 
34  if (n_total_pairs == 0) {
35  return 0;
36  }
37 
38  Gpu::DeviceVector<Index> offsets(n_total_pairs);
39  Index* AMREX_RESTRICT p_offsets = offsets.dataPtr();
40 
41  // The following is used to calculate the appropriate offsets. Note that
42  // a standard cummulative sum is not appropriate since the mask is also
43  // used to specify the type of collision and can therefore have values >1
44  auto const num_added = amrex::Scan::PrefixSum<Index>(n_total_pairs,
45  [=] AMREX_GPU_DEVICE (Index i) -> Index { return mask[i] ? 1 : 0; },
46  [=] AMREX_GPU_DEVICE (Index i, Index s) { p_offsets[i] = s; },
48  );
49 
50  const auto ptile1_index = ptile1.numParticles();
51  const auto ptile2_index = ptile2.numParticles();
52  ptile1.resize(ptile1_index + num_added);
53  ptile2.resize(ptile2_index + num_added);
54 
55  const auto ptile1_data = ptile1.getParticleTileData();
56  const auto ptile2_data = ptile2.getParticleTileData();
57 
58  const Long minus_one_long = -1;
59 
60  ParallelForRNG(n_total_pairs,
61  [=] AMREX_GPU_DEVICE (int i, RandomEngine const& engine) noexcept
62  {
63  if (mask[i])
64  {
65  // First, make copies of the colliding particles
66  copy1(ptile1_data, ptile1_data, p_pair_indices_1[i], p_offsets[i] + ptile1_index, engine);
67  copy2(ptile2_data, ptile2_data, p_pair_indices_2[i], p_offsets[i] + ptile2_index, engine);
68 
69  // Now we adjust the properties of the original and child particles,
70  // starting with the parent particles
71  auto& w1 = ptile1_data.m_rdata[PIdx::w][p_pair_indices_1[i]];
72  auto& w2 = ptile2_data.m_rdata[PIdx::w][p_pair_indices_2[i]];
73 
74  // Remove p_pair_reaction_weight[i] from the colliding particles' weights.
75  // If the colliding particle weight decreases to zero, remove particle by
76  // setting its id to -1.
77  Gpu::Atomic::AddNoRet(&w1, -p_pair_reaction_weight[i]);
78  if (w1 <= 0._prt) {
79  auto& p = ptile1_data.m_aos[p_pair_indices_1[i]];
80  p.atomicSetID(minus_one_long);
81  }
82 
83  Gpu::Atomic::AddNoRet(&w2, -p_pair_reaction_weight[i]);
84  if (w2 <= 0._prt) {
85  auto& p = ptile2_data.m_aos[p_pair_indices_2[i]];
86  p.atomicSetID(minus_one_long);
87  }
88 
89  // Set the child particle properties appropriately
90  ptile1_data.m_rdata[PIdx::w][p_offsets[i] + ptile1_index] = p_pair_reaction_weight[i];
91  ptile2_data.m_rdata[PIdx::w][p_offsets[i] + ptile2_index] = p_pair_reaction_weight[i];
92 
93  auto& ux1 = ptile1_data.m_rdata[PIdx::ux][p_offsets[i] + ptile1_index];
94  auto& uy1 = ptile1_data.m_rdata[PIdx::uy][p_offsets[i] + ptile1_index];
95  auto& uz1 = ptile1_data.m_rdata[PIdx::uz][p_offsets[i] + ptile1_index];
96  auto& ux2 = ptile2_data.m_rdata[PIdx::ux][p_offsets[i] + ptile2_index];
97  auto& uy2 = ptile2_data.m_rdata[PIdx::uy][p_offsets[i] + ptile2_index];
98  auto& uz2 = ptile2_data.m_rdata[PIdx::uz][p_offsets[i] + ptile2_index];
99 
100  // for simplicity (for now) we assume non-relativistic particles
101  // and simply calculate the center-of-momentum velocity from the
102  // rest masses
103  auto const uCOM_x = (m1 * ux1 + m2 * ux2) / (m1 + m2);
104  auto const uCOM_y = (m1 * uy1 + m2 * uy2) / (m1 + m2);
105  auto const uCOM_z = (m1 * uz1 + m2 * uz2) / (m1 + m2);
106 
107  // transform to COM frame
108  ux1 -= uCOM_x;
109  uy1 -= uCOM_y;
110  uz1 -= uCOM_z;
111  ux2 -= uCOM_x;
112  uy2 -= uCOM_y;
113  uz2 -= uCOM_z;
114 
115  if (mask[i] == int(ScatteringProcessType::ELASTIC)) {
116  // randomly rotate the velocity vector for the first particle
118  ux1, uy1, uz1, std::sqrt(ux1*ux1 + uy1*uy1 + uz1*uz1), engine
119  );
120  // set the second particles velocity so that the total momentum
121  // is zero
122  ux2 = -ux1 * m1 / m2;
123  uy2 = -uy1 * m1 / m2;
124  uz2 = -uz1 * m1 / m2;
125  } else if (mask[i] == int(ScatteringProcessType::BACK)) {
126  // reverse the velocity vectors of both particles
127  ux1 *= -1.0_prt;
128  uy1 *= -1.0_prt;
129  uz1 *= -1.0_prt;
130  ux2 *= -1.0_prt;
131  uy2 *= -1.0_prt;
132  uz2 *= -1.0_prt;
133  } else if (mask[i] == int(ScatteringProcessType::CHARGE_EXCHANGE)) {
134  if (m1 == m2) {
135  auto const temp_ux = ux1;
136  auto const temp_uy = uy1;
137  auto const temp_uz = uz1;
138  ux1 = ux2;
139  uy1 = uy2;
140  uz1 = uz2;
141  ux2 = temp_ux;
142  uy2 = temp_uy;
143  uz2 = temp_uz;
144  }
145  else {
146  Abort("Uneven mass charge-exchange not implemented yet.");
147  }
148  }
149  else {
150  Abort("Unknown scattering process.");
151  }
152  // transform back to labframe
153  ux1 += uCOM_x;
154  uy1 += uCOM_y;
155  uz1 += uCOM_z;
156  ux2 += uCOM_x;
157  uy2 += uCOM_y;
158  uz2 += uCOM_z;
159  }
160  });
161 
163  return static_cast<int>(num_added);
164 }
165 #endif // SPLIT_AND_SCATTER_FUNC_H_
#define AMREX_RESTRICT
#define AMREX_GPU_DEVICE
Array4< int const > mask
int splitScatteringParticles(const index_type &n_total_pairs, Tile &ptile1, Tile &ptile2, const Index *AMREX_RESTRICT mask, CopyFunc &&copy1, CopyFunc &&copy2, const amrex::ParticleReal m1, const amrex::ParticleReal m2, 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) noexcept
Function that performs the particle scattering and injection due to binary collisions.
Definition: SplitAndScatterFunc.H:22
T * dataPtr() noexcept
AMREX_GPU_HOST_DEVICE AMREX_INLINE void RandomizeVelocity(amrex::ParticleReal &ux, amrex::ParticleReal &uy, amrex::ParticleReal &uz, const amrex::ParticleReal vp, amrex::RandomEngine const &engine)
Function to perform scattering of a particle that results in a random velocity vector with given magn...
Definition: ParticleUtils.H:161
ParticleBins::index_type index_type
Definition: ParticleUtils.cpp:32
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
void synchronize() noexcept
static constexpr struct amrex::Scan::Type::Exclusive exclusive
static constexpr RetSum retSum
void ParallelForRNG(T n, L &&f) noexcept
typename std::enable_if< B, T >::type EnableIf_t
void Abort(const std::string &msg)
i
Definition: check_interp_points_and_weights.py:174
s
Definition: plot_results.py:104
@ uz
Definition: NamedComponentParticleContainer.H:27
@ w
weight
Definition: NamedComponentParticleContainer.H:26
@ uy
Definition: NamedComponentParticleContainer.H:27
@ ux
Definition: NamedComponentParticleContainer.H:27