WarpX
Loading...
Searching...
No Matches
SplitAndScatterFunc.H
Go to the documentation of this file.
1/* Copyright 2023-2024 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 WARPX_SPLIT_AND_SCATTER_FUNC_H_
10#define WARPX_SPLIT_AND_SCATTER_FUNC_H_
11
16#include "Utils/ParticleUtils.H"
17
23{
24 // Define shortcuts for frequently-used type names
27 using ParticleTileDataType = typename ParticleTileType::ParticleTileDataType;
30 using SoaData_type = WarpXParticleContainer::ParticleTileType::ParticleTileDataType;
31
32public:
36 SplitAndScatterFunc () = default;
37
44 SplitAndScatterFunc (const std::string& collision_name, MultiParticleContainer const * mypc);
45
54 const index_type& n_total_pairs,
55 ParticleTileType& ptile1, ParticleTileType& ptile2,
57 ParticleTileType** AMREX_RESTRICT tile_products,
58 const amrex::ParticleReal m1, const amrex::ParticleReal m2,
59 const amrex::Vector<amrex::ParticleReal>& /*products_mass*/,
61 amrex::Vector<index_type>& products_np,
62 const SmartCopy* AMREX_RESTRICT copy_species1,
63 const SmartCopy* AMREX_RESTRICT copy_species2,
64 const index_type* AMREX_RESTRICT p_pair_indices_1,
65 const index_type* AMREX_RESTRICT p_pair_indices_2,
66 const amrex::ParticleReal* AMREX_RESTRICT p_pair_reaction_weight,
67 const amrex::ParticleReal* /*p_product_data*/ ) const
68 {
69 using namespace amrex::literals;
70
71 // Return a vector of zeros, indicating that for all the "product" species
72 // there were no new particles added.
73 if (n_total_pairs == 0) { return amrex::Vector<int>(m_num_product_species, 0); }
74
75 // The following is used to calculate the appropriate offsets for processes
76 // that do not produce macroparticles in new species (i.e., not ionization, not charge exchange).
77 // Note that a standard cummulative sum is not appropriate since the
78 // mask is also used to specify the type of collision and can therefore
79 // have values >1
80 amrex::Gpu::DeviceVector<index_type> no_product_offsets(n_total_pairs);
81 index_type* AMREX_RESTRICT no_product_offsets_data = no_product_offsets.data();
82 const index_type* AMREX_RESTRICT no_product_p_offsets = no_product_offsets.dataPtr();
83 auto const no_product_total = amrex::Scan::PrefixSum<index_type>(n_total_pairs,
85 return ((mask[i] > 0) &
87 (mask[i] != int(ScatteringProcessType::CHARGE_EXCHANGE))) ? 1 : 0;
88 },
89 [=] AMREX_GPU_DEVICE (index_type i, index_type s) { no_product_offsets_data[i] = s; },
91 );
92
94 for (int i = 0; i < 2; i++)
95 {
96 // Record the number of non product producing events lead to new
97 // particles for species1 and 2. Only 1 particle is created for
98 // each species (the piece that breaks off to have equal weight)
99 // particles.
100 num_added_vec[i] = static_cast<int>(no_product_total);
101 }
102
103 // The following is used to calculate the appropriate offsets for
104 // product producing processes (i.e., ionization and charge exchange).
105 // Note that a standard cummulative sum is not appropriate since the
106 // mask is also used to specify the type of collision and can therefore
107 // have values >1
108 amrex::Gpu::DeviceVector<index_type> with_product_offsets(n_total_pairs);
109 index_type* AMREX_RESTRICT with_product_offsets_data = with_product_offsets.data();
110 const index_type* AMREX_RESTRICT with_product_p_offsets = with_product_offsets.dataPtr();
111 auto const with_product_total = amrex::Scan::PrefixSum<index_type>(n_total_pairs,
113 return ((mask[i] == int(ScatteringProcessType::IONIZATION)) |
114 (mask[i] == int(ScatteringProcessType::CHARGE_EXCHANGE))) ? 1 : 0;
115 },
116 [=] AMREX_GPU_DEVICE (index_type i, index_type s) { with_product_offsets_data[i] = s; },
118 );
119
120 for (int i = 0; i < m_num_product_species; i++)
121 {
122 // Add the number of product producing events to the species involved in those processes.
123 int num_products = m_num_products_host[i];
124 const index_type num_added = with_product_total * num_products;
125 num_added_vec[i] += static_cast<int>(num_added);
126 }
127
128 // resize the particle tiles to accomodate the new particles
129 // The code works correctly, even if the same species appears
130 // several times in the product species list.
131 // (e.g., for e- + H -> 2 e- + H+, the product species list is [e-, H, e-, H+])
132 // In that case, the species that appears multiple times is resized several times ;
133 // `products_np` keeps track of array positions at which it has been resized.
134 for (int i = 0; i < m_num_product_species; i++)
135 {
136 products_np[i] = tile_products[i]->numParticles();
137 tile_products[i]->resize(products_np[i] + num_added_vec[i]);
138 }
139
140 const auto soa_1 = ptile1.getParticleTileData();
141 const auto soa_2 = ptile2.getParticleTileData();
142
143 // Create necessary GPU vectors, that will be used in the kernel below
144 amrex::Vector<SoaData_type> soa_products;
145 for (int i = 0; i < m_num_product_species; i++)
146 {
147 soa_products.push_back(tile_products[i]->getParticleTileData());
148 }
149#ifdef AMREX_USE_GPU
152
154 soa_products.end(),
155 device_soa_products.begin());
157 products_np.end(),
158 device_products_np.begin());
159
161 SoaData_type* AMREX_RESTRICT soa_products_data = device_soa_products.data();
162 const index_type* AMREX_RESTRICT products_np_data = device_products_np.data();
163#else
164 SoaData_type* AMREX_RESTRICT soa_products_data = soa_products.data();
165 const index_type* AMREX_RESTRICT products_np_data = products_np.data();
166#endif
167
168 const int num_product_species = m_num_product_species;
169 const auto ionization_energy = m_ionization_energy;
170
171 // Grab the masses of reaction products
172 amrex::ParticleReal mass_product1 = 0;
173 amrex::ParticleReal mass_product2 = 0;
174 if (num_product_species > 2) {
175 mass_product1 = pc_products[2]->getMass();
176 mass_product2 = pc_products[3]->getMass();
177 }
178
179 // First perform all non-product producing collisions
180 amrex::ParallelForRNG(n_total_pairs,
181 [=] AMREX_GPU_DEVICE (int i, amrex::RandomEngine const& engine) noexcept
182 {
184 {
185 const auto product1_index = products_np_data[0] + no_product_p_offsets[i];
186 // Make a copy of the particle from species 1
187 copy_species1[0](soa_products_data[0], soa_1, static_cast<int>(p_pair_indices_1[i]),
188 static_cast<int>(product1_index), engine);
189 // Set the weight of the new particles to p_pair_reaction_weight[i]
190 soa_products_data[0].m_rdata[PIdx::w][product1_index] = p_pair_reaction_weight[i];
191
192 const auto product2_index = products_np_data[1] + no_product_p_offsets[i];
193 // Make a copy of the particle from species 2
194 copy_species2[1](soa_products_data[1], soa_2, static_cast<int>(p_pair_indices_2[i]),
195 static_cast<int>(product2_index), engine);
196 // Set the weight of the new particles to p_pair_reaction_weight[i]
197 soa_products_data[1].m_rdata[PIdx::w][product2_index] = p_pair_reaction_weight[i];
198
199 // Set the child particle properties appropriately
200 auto& ux1 = soa_products_data[0].m_rdata[PIdx::ux][product1_index];
201 auto& uy1 = soa_products_data[0].m_rdata[PIdx::uy][product1_index];
202 auto& uz1 = soa_products_data[0].m_rdata[PIdx::uz][product1_index];
203 auto& ux2 = soa_products_data[1].m_rdata[PIdx::ux][product2_index];
204 auto& uy2 = soa_products_data[1].m_rdata[PIdx::uy][product2_index];
205 auto& uz2 = soa_products_data[1].m_rdata[PIdx::uz][product2_index];
206
207#if (defined WARPX_DIM_RZ)
208 /* In RZ geometry, macroparticles can collide with other macroparticles
209 * in the same *cylindrical* cell. For this reason, collisions between macroparticles
210 * are actually not local in space. In this case, the underlying assumption is that
211 * particles within the same cylindrical cell represent a cylindrically-symmetry
212 * momentum distribution function. Therefore, here, we temporarily rotate the
213 * momentum of one of the macroparticles in agreement with this cylindrical symmetry.
214 * (This is technically only valid if we use only the m=0 azimuthal mode in the simulation;
215 * there is a corresponding assert statement at initialization.)
216 */
217 amrex::ParticleReal const theta = (
218 soa_products_data[1].m_rdata[PIdx::theta][product2_index]
219 - soa_products_data[0].m_rdata[PIdx::theta][product1_index]
220 );
221 amrex::ParticleReal const ux1buf = ux1;
222 ux1 = ux1buf*std::cos(theta) - uy1*std::sin(theta);
223 uy1 = ux1buf*std::sin(theta) + uy1*std::cos(theta);
224#endif
225
226 // for simplicity (for now) we assume non-relativistic particles
227 // and simply calculate the center-of-momentum velocity from the
228 // rest masses
229 auto const uCOM_x = (m1 * ux1 + m2 * ux2) / (m1 + m2);
230 auto const uCOM_y = (m1 * uy1 + m2 * uy2) / (m1 + m2);
231 auto const uCOM_z = (m1 * uz1 + m2 * uz2) / (m1 + m2);
232
233 // transform to COM frame
234 ux1 -= uCOM_x;
235 uy1 -= uCOM_y;
236 uz1 -= uCOM_z;
237 ux2 -= uCOM_x;
238 uy2 -= uCOM_y;
239 uz2 -= uCOM_z;
240
241 if (mask[i] == int(ScatteringProcessType::ELASTIC)) {
242 // randomly rotate the velocity vector for the first particle
244 ux1, uy1, uz1, std::sqrt(ux1*ux1 + uy1*uy1 + uz1*uz1), engine
245 );
246 // set the second particles velocity so that the total momentum
247 // is zero
248 ux2 = -ux1 * m1 / m2;
249 uy2 = -uy1 * m1 / m2;
250 uz2 = -uz1 * m1 / m2;
251 } else if (mask[i] == int(ScatteringProcessType::BACK)) {
252 // reverse the velocity vectors of both particles
253 ux1 *= -1.0_prt;
254 uy1 *= -1.0_prt;
255 uz1 *= -1.0_prt;
256 ux2 *= -1.0_prt;
257 uy2 *= -1.0_prt;
258 uz2 *= -1.0_prt;
259 } else if (mask[i] == int(ScatteringProcessType::FORWARD)) {
260 amrex::Abort("Forward scattering with DSMC not implemented yet.");
261 }
262 else {
263 amrex::Abort("Unknown scattering process.");
264 }
265 // transform back to labframe
266 ux1 += uCOM_x;
267 uy1 += uCOM_y;
268 uz1 += uCOM_z;
269 ux2 += uCOM_x;
270 uy2 += uCOM_y;
271 uz2 += uCOM_z;
272
273#if (defined WARPX_DIM_RZ)
274 /* Undo the earlier velocity rotation. */
275 amrex::ParticleReal const ux1buf_new = ux1;
276 ux1 = ux1buf_new*std::cos(-theta) - uy1*std::sin(-theta);
277 uy1 = ux1buf_new*std::sin(-theta) + uy1*std::cos(-theta);
278#endif
279 }
280
281 // Next perform all product-producing collisions
283 {
284 // create a copy of the first product species at the location of species 1
285 const auto product1_index = products_np_data[2] + with_product_p_offsets[i];
286 copy_species1[2](soa_products_data[2], soa_1, static_cast<int>(p_pair_indices_1[i]),
287 static_cast<int>(product1_index), engine);
288 // Set the weight of the new particle to p_pair_reaction_weight[i]
289 soa_products_data[2].m_rdata[PIdx::w][product1_index] = p_pair_reaction_weight[i];
290
291 // create a copy of the other product species at the location of species 2
292 const auto product2_index = products_np_data[3] + with_product_p_offsets[i];
293 copy_species2[3](soa_products_data[3], soa_2, static_cast<int>(p_pair_indices_2[i]),
294 static_cast<int>(product2_index), engine);
295 // Set the weight of the new particle to p_pair_reaction_weight[i]
296 soa_products_data[3].m_rdata[PIdx::w][product2_index] = p_pair_reaction_weight[i];
297 }
298 else if (mask[i] == int(ScatteringProcessType::IONIZATION))
299 {
300 const auto species1_index = products_np_data[0] + no_product_total + with_product_p_offsets[i];
301 // Make a copy of the particle from species 1
302 copy_species1[0](soa_products_data[0], soa_1, static_cast<int>(p_pair_indices_1[i]),
303 static_cast<int>(species1_index), engine);
304 // Set the weight of the new particles to p_pair_reaction_weight[i]
305 soa_products_data[0].m_rdata[PIdx::w][species1_index] = p_pair_reaction_weight[i];
306
307 // create a copy of the first product species at the location of species 2
308 // (species2 is the "target species", i.e. the species that is ionized)
309 const auto product1_index = products_np_data[2] + with_product_p_offsets[i];
310 copy_species2[2](soa_products_data[2], soa_2, static_cast<int>(p_pair_indices_2[i]),
311 static_cast<int>(product1_index), engine);
312 // Set the weight of the new particle to p_pair_reaction_weight[i]
313 soa_products_data[2].m_rdata[PIdx::w][product1_index] = p_pair_reaction_weight[i];
314
315 // create a copy of the other product species at the location of species 2
316 // (species2 is the "target species", i.e. the species that is ionized)
317 const auto product2_index = products_np_data[3] + with_product_p_offsets[i];
318 copy_species2[3](soa_products_data[3], soa_2, static_cast<int>(p_pair_indices_2[i]),
319 static_cast<int>(product2_index), engine);
320 // Set the weight of the new particle to p_pair_reaction_weight[i]
321 soa_products_data[3].m_rdata[PIdx::w][product2_index] = p_pair_reaction_weight[i];
322
323 // Grab the colliding particle velocities to calculate the COM
324 // Note that the two product particles currently have the same
325 // velocity as the "target" particle
326 auto& ux1 = soa_products_data[0].m_rdata[PIdx::ux][species1_index];
327 auto& uy1 = soa_products_data[0].m_rdata[PIdx::uy][species1_index];
328 auto& uz1 = soa_products_data[0].m_rdata[PIdx::uz][species1_index];
329 auto& ux_p1 = soa_products_data[2].m_rdata[PIdx::ux][product1_index];
330 auto& uy_p1 = soa_products_data[2].m_rdata[PIdx::uy][product1_index];
331 auto& uz_p1 = soa_products_data[2].m_rdata[PIdx::uz][product1_index];
332 auto& ux_p2 = soa_products_data[3].m_rdata[PIdx::ux][product2_index];
333 auto& uy_p2 = soa_products_data[3].m_rdata[PIdx::uy][product2_index];
334 auto& uz_p2 = soa_products_data[3].m_rdata[PIdx::uz][product2_index];
335
336#if (defined WARPX_DIM_RZ)
337 /* In RZ geometry, macroparticles can collide with other macroparticles
338 * in the same *cylindrical* cell. For this reason, collisions between macroparticles
339 * are actually not local in space. In this case, the underlying assumption is that
340 * particles within the same cylindrical cell represent a cylindrically-symmetry
341 * momentum distribution function. Therefore, here, we temporarily rotate the
342 * momentum of one of the macroparticles in agreement with this cylindrical symmetry.
343 * (This is technically only valid if we use only the m=0 azimuthal mode in the simulation;
344 * there is a corresponding assert statement at initialization.)
345 */
346 amrex::ParticleReal const theta = (
347 soa_products_data[2].m_rdata[PIdx::theta][product1_index]
348 - soa_products_data[0].m_rdata[PIdx::theta][species1_index]
349 );
350 amrex::ParticleReal const ux1buf = ux1;
351 ux1 = ux1buf*std::cos(theta) - uy1*std::sin(theta);
352 uy1 = ux1buf*std::sin(theta) + uy1*std::cos(theta);
353#endif
354
355 // for simplicity (for now) we assume non-relativistic particles
356 // and simply calculate the center-of-momentum velocity from the
357 // rest masses
358 auto const uCOM_x = (m1 * ux1 + m2 * ux_p2) / (m1 + m2);
359 auto const uCOM_y = (m1 * uy1 + m2 * uy_p2) / (m1 + m2);
360 auto const uCOM_z = (m1 * uz1 + m2 * uz_p2) / (m1 + m2);
361
362 // transform to COM frame
363 ux1 -= uCOM_x;
364 uy1 -= uCOM_y;
365 uz1 -= uCOM_z;
366 ux_p1 -= uCOM_x;
367 uy_p1 -= uCOM_y;
368 uz_p1 -= uCOM_z;
369 ux_p2 -= uCOM_x;
370 uy_p2 -= uCOM_y;
371 uz_p2 -= uCOM_z;
372
373 // calculate kinetic energy of the collision (in eV)
374 const amrex::ParticleReal E1 = (
375 0.5_prt * m1 * (ux1*ux1 + uy1*uy1 + uz1*uz1) / PhysConst::q_e
376 );
377 const amrex::ParticleReal E2 = (
378 0.5_prt * m2 * (ux_p2*ux_p2 + uy_p2*uy_p2 + uz_p2*uz_p2) / PhysConst::q_e
379 );
380 const amrex::ParticleReal E_coll = E1 + E2;
381
382 // subtract the energy cost for ionization
383 const amrex::ParticleReal E_out = (E_coll - ionization_energy) * PhysConst::q_e;
384
385 // Momentum and energy division after the ionization event
386 // is done as follows:
387 // Three numbers are generated that satisfy the triangle
388 // inequality. These numbers will be scaled to give the
389 // momentum for each particle (satisfying the triangle
390 // inequality ensures that the momentum vectors can be
391 // arranged such that the net linear momentum is zero).
392 // Product 2 is definitely an ion, so we first choose its
393 // proportion to be n_2 = min(E2 / E_coll, 0.5 * R), where
394 // R is a random number between 0 and 1.
395 // The other two numbers (n_0 & n_1) are then found
396 // by choosing a random point on the ellipse characterized
397 // by the semi-major and semi-minor axes
398 // a = (1 - n_0) / 2.0
399 // b = 0.5 * sqrt(1 - 2 * n_0)
400 // The numbers are found by randomly sampling an x value
401 // between -a and a, and finding the corresponding y value
402 // that falls on the ellipse: y^2 = b^2 - b^2/a^2 * x^2.
403 // Then n_0 = sqrt(y^2 + (x - n_2/2)^2) and
404 // n_1 = 1 - n_2 - n_0.
405 // Next, we need to find the number C, such that if
406 // p_i = C * n_i, we would have E_0 + E_1 + E_2 = E_out
407 // where E_i = p_i^2 / (2 M_i), i.e.,
408 // C^2 * \sum_i [n_i^2 / (2 M_i)] = E_out
409 // After C is determined the momentum vectors are arranged
410 // such that the net linear momentum is zero.
411
412 const amrex::ParticleReal n_2 = std::min(E2 / E_coll, 0.5_prt * static_cast<amrex::ParticleReal>(amrex::Random(engine)));
413
414 // find ellipse semi-major and minor axis
415 const amrex::ParticleReal a = 0.5_prt * (1.0_prt - n_2);
416 const amrex::ParticleReal b = 0.5_prt * std::sqrt(1.0_prt - 2.0_prt * n_2);
417
418 // sample random x value and calculate y
419 const amrex::ParticleReal x = (2._prt * amrex::Random(engine) - 1.0_prt) * a;
420 const amrex::ParticleReal y2 = b*b - b*b/(a*a) * x*x;
421 const amrex::ParticleReal n_0 = std::sqrt(y2 + x*x - x*n_2 + 0.25_prt*n_2*n_2);
422 const amrex::ParticleReal n_1 = 1.0_prt - n_0 - n_2;
423
424 // calculate the value of C
425 const amrex::ParticleReal C = std::sqrt(E_out / (
426 n_0*n_0 / (2.0_prt * m1) + n_1*n_1 / (2.0_prt * mass_product1) + n_2*n_2 / (2.0_prt * mass_product2)
427 ));
428
429 // Now that appropriate momenta are set for each outgoing species
430 // the directions for the velocity vectors must be chosen such
431 // that the net linear momentum in the current frame is 0.
432 // This is achieved by arranging the momentum vectors in
433 // a triangle and finding the required angles between the vectors.
434 const amrex::ParticleReal cos_alpha = (n_0*n_0 + n_1*n_1 - n_2*n_2) / (2.0_prt * n_0 * n_1);
435 const amrex::ParticleReal sin_alpha = std::sqrt(1.0_prt - cos_alpha*cos_alpha);
436 const amrex::ParticleReal cos_gamma = (n_0*n_0 + n_2*n_2 - n_1*n_1) / (2.0_prt * n_0 * n_2);
437 const amrex::ParticleReal sin_gamma = std::sqrt(1.0_prt - cos_gamma*cos_gamma);
438
439 // choose random theta and phi values (orientation of the triangle)
440 const amrex::ParticleReal Theta = amrex::Random(engine) * 2.0_prt * MathConst::pi;
441 const amrex::ParticleReal phi = amrex::Random(engine) * MathConst::pi;
442
443 const amrex::ParticleReal cos_theta = std::cos(Theta);
444 const amrex::ParticleReal sin_theta = std::sin(Theta);
445 const amrex::ParticleReal cos_phi = std::cos(phi);
446 const amrex::ParticleReal sin_phi = std::sin(phi);
447
448 // calculate the velocity components for each particle
449 ux1 = C * n_0 / m1 * cos_theta * cos_phi;
450 uy1 = C * n_0 / m1 * cos_theta * sin_phi;
451 uz1 = -C * n_0 / m1 * sin_theta;
452
453 ux_p1 = C * n_1 / mass_product1 * (-cos_alpha * cos_theta * cos_phi - sin_alpha * sin_phi);
454 uy_p1 = C * n_1 / mass_product1 * (-cos_alpha * cos_theta * sin_phi + sin_alpha * cos_phi);
455 uz_p1 = C * n_1 / mass_product1 * (cos_alpha * sin_theta);
456
457 ux_p2 = C * n_2 / mass_product2 * (-cos_gamma * cos_theta * cos_phi + sin_gamma * sin_phi);
458 uy_p2 = C * n_2 / mass_product2 * (-cos_gamma * cos_theta * sin_phi - sin_gamma * cos_phi);
459 uz_p2 = C * n_2 / mass_product2 * (cos_gamma * sin_theta);
460
461 // transform back to labframe
462 ux1 += uCOM_x;
463 uy1 += uCOM_y;
464 uz1 += uCOM_z;
465 ux_p1 += uCOM_x;
466 uy_p1 += uCOM_y;
467 uz_p1 += uCOM_z;
468 ux_p2 += uCOM_x;
469 uy_p2 += uCOM_y;
470 uz_p2 += uCOM_z;
471
472#if (defined WARPX_DIM_RZ)
473 /* Undo the earlier velocity rotation. */
474 amrex::ParticleReal const ux1buf_new = ux1;
475 ux1 = ux1buf_new*std::cos(-theta) - uy1*std::sin(-theta);
476 uy1 = ux1buf_new*std::sin(-theta) + uy1*std::cos(-theta);
477#endif
478 }
479 });
480
481 // Initialize the user runtime components
482 for (int i = 0; i < m_num_product_species; i++)
483 {
484 const int start_index = int(products_np[i]);
485 const int stop_index = int(products_np[i] + num_added_vec[i]);
487 0, 0,
488 pc_products[i]->getUserRealAttribs(), pc_products[i]->getUserIntAttribs(),
489 pc_products[i]->GetRealSoANames(), pc_products[i]->GetIntSoANames(),
490 pc_products[i]->getUserRealAttribParser(),
491 pc_products[i]->getUserIntAttribParser(),
492#ifdef WARPX_QED
493 false, // do not initialize QED quantities, since they were initialized
494 // when calling the SmartCopy functors
495 pc_products[i]->get_breit_wheeler_engine_ptr(),
496 pc_products[i]->get_quantum_sync_engine_ptr(),
497#endif
498 pc_products[i]->getIonizationInitialLevel(),
499 start_index, stop_index);
500 }
501
503 return num_added_vec;
504 }
505
506private:
507 // How many different type of species the collision produces
509 // If ionization collisions are included, what is the energy cost
510 amrex::ParticleReal m_ionization_energy = 0.0;
511 // Vectors of size m_num_product_species storing how many particles of a given species are
512 // produced by a collision event.
515};
516#endif // WARPX_SPLIT_AND_SCATTER_FUNC_H_
#define AMREX_RESTRICT
#define AMREX_INLINE
#define AMREX_GPU_DEVICE
Array4< int const > mask
CollisionType
Definition BinaryCollisionUtils.H:17
@ BACK
Definition ScatteringProcess.H:23
@ CHARGE_EXCHANGE
Definition ScatteringProcess.H:24
@ ELASTIC
Definition ScatteringProcess.H:22
@ IONIZATION
Definition ScatteringProcess.H:26
@ FORWARD
Definition ScatteringProcess.H:27
Definition MultiParticleContainer.H:68
typename ParticleBins::index_type index_type
Definition SplitAndScatterFunc.H:29
typename ParticleTileType::ParticleTileDataType ParticleTileDataType
Definition SplitAndScatterFunc.H:27
int m_num_product_species
Definition SplitAndScatterFunc.H:508
SplitAndScatterFunc()=default
Default constructor of the SplitAndScatterFunc class.
typename WarpXParticleContainer::ParticleType ParticleType
Definition SplitAndScatterFunc.H:25
CollisionType m_collision_type
Definition SplitAndScatterFunc.H:514
amrex::DenseBins< ParticleTileDataType > ParticleBins
Definition SplitAndScatterFunc.H:28
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 > &, const index_type *AMREX_RESTRICT mask, 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 amrex::ParticleReal *) const
Function that performs the particle scattering and injection due to binary collisions.
Definition SplitAndScatterFunc.H:53
amrex::ParticleReal m_ionization_energy
Definition SplitAndScatterFunc.H:510
typename WarpXParticleContainer::ParticleTileType ParticleTileType
Definition SplitAndScatterFunc.H:26
amrex::Gpu::HostVector< int > m_num_products_host
Definition SplitAndScatterFunc.H:513
WarpXParticleContainer::ParticleTileType::ParticleTileDataType SoaData_type
Definition SplitAndScatterFunc.H:30
iterator begin() noexcept
T * dataPtr() noexcept
T * data() noexcept
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::vector< std::string > &particle_comps, const std::vector< std::string > &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
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:221
static constexpr auto q_e
elementary charge [C]
Definition constant.H:52
static constexpr amrex::Real pi
ratio of a circle's circumference to its diameter
Definition constant.H:23
void synchronize() noexcept
PinnedVector< T > HostVector
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr HostToDevice hostToDevice
void streamSynchronize() noexcept
PODVector< T, ArenaAllocator< T > > DeviceVector
static constexpr struct amrex::Scan::Type::Exclusive exclusive
static constexpr RetSum retSum
T PrefixSum(N n, FIN const &fin, FOUT const &fout, TYPE, RetSum a_ret_sum=retSum)
Real Random()
void Abort(const std::string &msg)
AMREX_ATTRIBUTE_FLATTEN_FOR void ParallelForRNG(T n, L const &f) noexcept
@ theta
RZ needs all three position components.
Definition WarpXParticleContainer.H:72
@ uz
Definition WarpXParticleContainer.H:70
@ w
weight
Definition WarpXParticleContainer.H:69
@ uy
Definition WarpXParticleContainer.H:70
@ ux
Definition WarpXParticleContainer.H:70
This is a functor for performing a "smart copy" that works in both host and device code.
Definition SmartCopy.H:34