Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binary-pairing Coulomb collisions: improvements and optimization #5047

Merged
merged 20 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Regression/Checksum/benchmarks_json/collisionISO.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"jz": 0.0
},
"electron": {
"particle_momentum_x": 3.5790777034053853e-19,
"particle_momentum_y": 3.5815348106229496e-19,
"particle_momentum_z": 3.577963316718249e-19,
"particle_position_x": 1.024180253191667,
"particle_position_y": 1.023919590453571,
"particle_position_z": 1.0240653505082926,
"particle_momentum_x": 3.578935809964031e-19,
"particle_momentum_y": 3.5778028343192025e-19,
"particle_momentum_z": 3.579884355240226e-19,
"particle_position_x": 1.0241442531780067,
"particle_position_y": 1.0238915904698023,
"particle_position_z": 1.024005350488445,
"particle_weight": 714240000000.0
}
}
20 changes: 10 additions & 10 deletions Regression/Checksum/benchmarks_json/collisionXZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
"Ez": 0.0
},
"ion": {
"particle_momentum_x": 2.5066842316209183e-19,
"particle_momentum_y": 2.2863311215256246e-19,
"particle_momentum_z": 2.2682377973998022e-19,
"particle_position_x": 2656041.6379113654,
"particle_position_y": 2669548.664572591,
"particle_momentum_x": 2.5057703758686855e-19,
"particle_momentum_y": 2.2923783859031756e-19,
"particle_momentum_z": 2.287625547039933e-19,
"particle_position_x": 2668340.55946334,
"particle_position_y": 2656508.8960297015,
"particle_weight": 1.7256099431746894e+26
},
"electron": {
"particle_momentum_x": 1.0390618975838188e-19,
"particle_momentum_y": 1.0241645067704406e-19,
"particle_momentum_z": 1.0173387880649568e-19,
"particle_position_x": 2646162.5818311535,
"particle_position_y": 2661127.0162632912,
"particle_momentum_x": 1.0375566570110091e-19,
"particle_momentum_y": 1.0149787104927666e-19,
"particle_momentum_z": 1.014560693540464e-19,
"particle_position_x": 2649873.564016985,
"particle_position_y": 2662401.3054512525,
"particle_weight": 1.7256099431746894e+26
}
}
10 changes: 5 additions & 5 deletions Regression/Checksum/benchmarks_json/collisionZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"jz": 0.0
},
"ions": {
"particle_momentum_x": 3.424633029669351e-16,
"particle_momentum_y": 3.429026824477811e-16,
"particle_momentum_z": 5.528396735566589e-16,
"particle_position_x": 720.0708684755696,
"particle_weight": 1.0999999999999997e+24
"particle_momentum_x": 3.427967883959658e-16,
"particle_momentum_y": 3.4356969098723214e-16,
"particle_momentum_z": 5.525919423123455e-16,
"particle_position_x": 720.0513313558002,
"particle_weight": 1.0999999999999996e+24
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
* @param[in] dt is the time step length between two collision calls.
* @param[in] L is the Coulomb log and will be used if greater than zero,
* otherwise will be computed.
* @param[in] dV is the volume of the corresponding cell.
* @param[in] engine the random number generator state & factory
* @param[in] isSameSpecies whether this is an intra-species collision process
* @param[in] coll_idx is the collision index offset.
*/

Expand Down Expand Up @@ -81,6 +83,9 @@ void ElasticCollisionPerez (
// bmax (screening length) cannot be smaller than atomic spacing
const T_PR bmax = amrex::max(lmdD, rmin);

// set max cross section based on mfp = atomic spacing
const T_PR sigma_max = T_PR(1.0) / (maxn * rmin);

#if (defined WARPX_DIM_RZ)
T_PR * const AMREX_RESTRICT theta1 = soa_1.m_rdata[PIdx::theta];
T_PR * const AMREX_RESTRICT theta2 = soa_2.m_rdata[PIdx::theta];
Expand Down Expand Up @@ -114,7 +119,7 @@ void ElasticCollisionPerez (
// scattering path s12 in UpdateMomentumPerezElastic().
// s12 is defined such that the expected value of the change in particle
// velocity is equal to that from the full NxN pairing method, as described
// here https://arxiv.org/submit/5758216/view. This method is a direct extension
// here https://arxiv.org/abs/2407.19151. This method is a direct extension
// of the original method by Takizuka and Abe JCP 25 (1977) to weighted particles.
T_PR n12;
const T_PR wpmax = amrex::max(w1[ I1[i1] ],w2[ I2[i2] ]);
Expand All @@ -124,10 +129,8 @@ void ElasticCollisionPerez (
UpdateMomentumPerezElastic(
u1x[ I1[i1] ], u1y[ I1[i1] ], u1z[ I1[i1] ],
u2x[ I2[i2] ], u2y[ I2[i2] ], u2z[ I2[i2] ],
n1, n2, n12,
q1, m1, w1[ I1[i1] ], q2, m2, w2[ I2[i2] ],
dt, L, bmax,
engine);
n12, sigma_max, L, bmax, dt, engine );

#if (defined WARPX_DIM_RZ)
T_PR const u1xbuf_new = u1x[I1[i1]];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* @param[in] L is the Coulomb log. A fixed L will be used if L > 0,
* otherwise L will be calculated based on the algorithm.
* @param[in] n12 = max(w1,w2)*min(N1,N2)/dV is the effective density used for s12
* @param[in] sigma_max is the maximum cross section based on mfp = atomic spacing
* used for the normalized scattering length s12 (see Sec. II.C of Perez et al.)
* To see if there are nan or inf updated velocities,
* compile with USE_ASSERTION=TRUE.
*
Expand All @@ -34,11 +36,11 @@ template <typename T_PR, typename T_R>
AMREX_GPU_HOST_DEVICE AMREX_INLINE
void UpdateMomentumPerezElastic (
T_PR& u1x, T_PR& u1y, T_PR& u1z, T_PR& u2x, T_PR& u2y, T_PR& u2z,
T_PR const n1, T_PR const n2, T_PR const n12,
T_PR const q1, T_PR const m1, T_PR const w1,
T_PR const q2, T_PR const m2, T_PR const w2,
T_R const dt, T_PR const L, T_PR const bmax,
amrex::RandomEngine const& engine)
T_PR const n12, T_PR const sigma_max,
T_PR const L, T_PR const bmax,
T_R const dt, amrex::RandomEngine const& engine )
{

T_PR const diffx = amrex::Math::abs(u1x-u2x);
Expand All @@ -64,7 +66,7 @@ void UpdateMomentumPerezElastic (
T_PR const p2y = u2y * m2;
T_PR const p2z = u2z * m2;

// Compute center-of-mass (COM) velocity and gamma
// Compute center-of-momentum (COM) velocity and gamma
T_PR const mass_g = m1 * g1 + m2 * g2;
T_PR const vcx = (p1x+p2x) / mass_g;
T_PR const vcy = (p1y+p2y) / mass_g;
Expand Down Expand Up @@ -103,86 +105,92 @@ void UpdateMomentumPerezElastic (
T_PR const g1s = ( T_PR(1.0) - vcDv1*inv_c2 )*gc*g1;
T_PR const g2s = ( T_PR(1.0) - vcDv2*inv_c2 )*gc*g2;

// Compute s
T_PR s = 0;
// Compute relative velocity in center-of-momentum frame
// (not a Lorentz invariant quantity)
T_PR const muRst = g1s*m1*g2s*m2/(g1s*m1 + g2s*m2);
T_PR const vrelst = p1sm/muRst; // |v1s - v2s|

// Compute invariant relative velocity in center-of-momentum frame
// (Lorentz invariant quantity)
T_PR const denom = T_PR(1.0) + p1sm*p1sm/(m1*g1s*m2*g2s)*inv_c2; // (1.0 - v1s*v2s/c^2)
T_PR const vrelst_invar = vrelst/denom; // |v1s - v2s|/(1.0 - v1s*v2s/c^2)

// Compute s12
T_PR s12 = 0;
if (p1sm > std::numeric_limits<T_PR>::min()) {

// s is non-zero (i.e. particles scatter) only if the relative
// motion between particles is not negligible (p1sm non-zero)
// Writing b0 in a form that is directly analagous to the well-known non-relativistic form.
// See Eq. 3.3.2 in Principles of Plasma Discharges and Material Processing by
// M. A. Lieberman and A. J. Lichtenberg.
// Note that b0 on Eq. 22 of Perez POP 19 (2012) is bmin = b0/2,
// Note: there is a typo in Eq 22 of Perez, the last square is incorrect!
// See the SMILEI documentation: https://smileipic.github.io/Smilei/Understand/collisions.html
// and https://github.com/ECP-WarpX/WarpX/files/3799803/main.pdf from GitHub #429
T_PR const b0 = amrex::Math::abs(q1*q2) /
(T_PR(2.0)*MathConst::pi*PhysConst::ep0*muRst*vrelst*vrelst_invar);


// Compute the Coulomb log lnLmd first
T_PR lnLmd;
if ( L > T_PR(0.0) ) { lnLmd = L; }
else
{
// Compute b0 according to eq (22) from Perez et al., Phys.Plasmas.19.083104 (2012)
// Note: there is a typo in the equation, the last square is incorrect!
// See the SMILEI documentation: https://smileipic.github.io/Smilei/Understand/collisions.html
// and https://github.com/ECP-WarpX/WarpX/files/3799803/main.pdf from GitHub #429
T_PR const b0 = amrex::Math::abs(q1*q2) * inv_c2 /
(T_PR(4.0)*MathConst::pi*PhysConst::ep0) * gc/mass_g *
( m1*g1s*m2*g2s/(p1sm*p1sm*inv_c2) + T_PR(1.0) );

// Compute the minimal impact parameter
constexpr T_PR hbar_pi = static_cast<T_PR>(PhysConst::hbar*MathConst::pi);
const T_PR bmin = amrex::max(hbar_pi/p1sm, b0);

// Compute the minimum impact parameter from quantum: bqm = lDB/(4*pi) = hbar/(2*p1sm)
// See NRL formulary. Also see "An introduction to the physics of the Coulomb logarithm,
// with emphasis on quantum-mechanical effects", J. Plasma Phys. vol. 85 (2019). by J.A. Krommes.
// Note: The formula in Perez 2012 and in Lee and More 1984 uses h rather than
// hbar for bqm. If this is used, then the transition energy where bmin goes from classical
// to quantum is only 2.5 eV for electrons; compared to 100 eV when using hbar.
JustinRayAngus marked this conversation as resolved.
Show resolved Hide resolved
const T_PR bmin_qm = static_cast<T_PR>(PhysConst::hbar*0.5/p1sm);

// Set the minimum impact parameter
const T_PR bmin = amrex::max(bmin_qm, T_PR(0.5)*b0);

// Compute the Coulomb log lnLmd
lnLmd = amrex::max( T_PR(2.0),
T_PR(0.5)*std::log(T_PR(1.0) + bmax*bmax/(bmin*bmin)) );
}

// Compute s
const auto tts = m1*g1s*m2*g2s/(inv_c2*p1sm*p1sm) + T_PR(1.0);
const auto tts2 = tts*tts;
s = n12 * dt*lnLmd*q1*q1*q2*q2 /
( T_PR(4.0) * MathConst::pi * PhysConst::ep0 * PhysConst::ep0 *
m1*g1*m2*g2/(inv_c2*inv_c2) ) * gc*p1sm/mass_g * tts2;

// Compute s'
const auto cbrt_n1 = std::cbrt(n1);
const auto cbrt_n2 = std::cbrt(n2);
const auto coeff = static_cast<T_PR>(
std::pow(4.0*MathConst::pi/3.0,1.0/3.0));
T_PR const vrel = mass_g*p1sm/(m1*g1s*m2*g2s*gc);
T_PR const sp = coeff * n12 * dt * vrel * (m1+m2) /
amrex::max( m1*cbrt_n1*cbrt_n1,
m2*cbrt_n2*cbrt_n2);

// Determine s
s = amrex::min(s,sp);
// Compute s12 with sigma limited by sigma_max where mfp = atomic spacing
JustinRayAngus marked this conversation as resolved.
Show resolved Hide resolved
// See https://github.com/user-attachments/files/16555064/CoulombScattering_s12.pdf
// for a proof that this expression for s12 is the same as Eq. 9 of Perez 2012 when
// sigma_eff = pi*b0^2*lnLmd
const T_PR sigma_eff = amrex::min(T_PR(MathConst::pi)*b0*b0*lnLmd,sigma_max);
s12 = sigma_eff * n12 * dt * vrelst * g1s*g2s/(g1*g2);

}

// Only modify momenta if is s is non-zero
if (s > std::numeric_limits<T_PR>::min()) {
// Only modify momenta if s12 is non-zero
if (s12 > std::numeric_limits<T_PR>::min()) {

// Get random numbers
T_PR r = amrex::Random(engine);

// Compute scattering angle
T_PR cosXs;
T_PR sinXs;
if ( s <= T_PR(0.1) )
if ( s12 <= T_PR(0.1) )
{
while ( true )
{
cosXs = T_PR(1.0) + s * std::log(r);
cosXs = T_PR(1.0) + s12 * std::log(r);
// Avoid the bug when r is too small such that cosXs < -1
if ( cosXs >= T_PR(-1.0) ) { break; }
r = amrex::Random(engine);
}
}
else if ( s > T_PR(0.1) && s <= T_PR(3.0) )
else if ( s12 > T_PR(0.1) && s12 <= T_PR(3.0) )
{
T_PR const Ainv = static_cast<T_PR>(
0.0056958 + 0.9560202*s - 0.508139*s*s +
0.47913906*s*s*s - 0.12788975*s*s*s*s + 0.02389567*s*s*s*s*s);
0.0056958 + 0.9560202*s12 - 0.508139*s12*s12 +
0.47913906*s12*s12*s12 - 0.12788975*s12*s12*s12*s12 + 0.02389567*s12*s12*s12*s12*s12);
cosXs = Ainv * std::log( std::exp(T_PR(-1.0)/Ainv) +
T_PR(2.0) * r * std::sinh(T_PR(1.0)/Ainv) );
}
else if ( s > T_PR(3.0) && s <= T_PR(6.0) )
else if ( s12 > T_PR(3.0) && s12 <= T_PR(6.0) )
{
T_PR const A = T_PR(3.0) * std::exp(-s);
T_PR const A = T_PR(3.0) * std::exp(-s12);
cosXs = T_PR(1.0)/A * std::log( std::exp(-A) +
T_PR(2.0) * r * std::sinh(A) );
}
Expand Down
Loading