WarpX
Loading...
Searching...
No Matches
LinearComptonInitializeMomentum.H
Go to the documentation of this file.
1/* Copyright 2023 Arianna Formenti
2 *
3 * This file is part of WarpX.
4 *
5 * License: BSD-3-Clause-LBNL
6 */
7
8#ifndef LINEAR_COMPTON_INITIALIZE_MOMENTUM_H
9#define LINEAR_COMPTON_INITIALIZE_MOMENTUM_H
10
12#include "Utils/ParticleUtils.H"
13#include "Utils/WarpXConst.H"
14
15#include <AMReX_DenseBins.H>
16#include <AMReX_Random.H>
17#include <AMReX_REAL.H>
18
19#include <cmath>
20#include <limits>
21
22namespace {
23 // Define shortcuts for frequently-used type names
24 using SoaData_type = WarpXParticleContainer::ParticleTileType::ParticleTileDataType;
27 using ParticleTileDataType = ParticleTileType::ParticleTileDataType;
29 using index_type = ParticleBins::index_type;
30
48 void LorentzTransformMomentum (
49 amrex::ParticleReal const& p_in, amrex::ParticleReal const& px_in, amrex::ParticleReal const& py_in, amrex::ParticleReal const& pz_in,
50 amrex::ParticleReal& p_out, amrex::ParticleReal& px_out, amrex::ParticleReal& py_out, amrex::ParticleReal& pz_out,
51 amrex::ParticleReal const& gamma, amrex::ParticleReal const& beta,
52 amrex::ParticleReal const& nx, amrex::ParticleReal const& ny, amrex::ParticleReal const& nz )
53 {
54 amrex::ParticleReal const p_parallel_in = nx*px_in + ny*py_in + nz*pz_in;
55 amrex::ParticleReal const p_parallel_out = gamma * ( p_parallel_in - beta * p_in );
56 p_out = gamma * ( p_in - beta * p_parallel_in );
57 px_out = px_in + nx * ( p_parallel_out - p_parallel_in );
58 py_out = py_in + ny * ( p_parallel_out - p_parallel_in );
59 pz_out = pz_in + nz * ( p_parallel_out - p_parallel_in );
60 }
61
77 void LinearComptonInitializeMomentum (
78 const SoaData_type& soa1_in, const SoaData_type& soa2_in,
79 SoaData_type& soa1_out, SoaData_type& soa2_out,
80 const index_type& idx1_in, const index_type& idx2_in,
81 const index_type& idx1_out_start, const index_type& idx2_out_start,
82 const amrex::RandomEngine& engine)
83 {
84 using namespace amrex::literals;
85
86 constexpr amrex::ParticleReal inv_c = 1._prt / PhysConst::c;
87 constexpr amrex::ParticleReal inv_csq = 1._prt / ( PhysConst::c * PhysConst::c );
88
89 // Extract the momenta of the incident particles
90 amrex::ParticleReal const photon_ux = soa1_in.m_rdata[PIdx::ux][idx1_in];
91 amrex::ParticleReal const photon_uy = soa1_in.m_rdata[PIdx::uy][idx1_in];
92 amrex::ParticleReal const photon_uz = soa1_in.m_rdata[PIdx::uz][idx1_in];
93 amrex::ParticleReal const lepton_ux = soa2_in.m_rdata[PIdx::ux][idx2_in];
94 amrex::ParticleReal const lepton_uy = soa2_in.m_rdata[PIdx::uy][idx2_in];
95 amrex::ParticleReal const lepton_uz = soa2_in.m_rdata[PIdx::uz][idx2_in];
96
97 // Transform the momentum of the incoming photon to the rest frame of the lepton
98 // - Prepare parameters of the Lorentz transformation
99 amrex::ParticleReal const lepton_u2 = (lepton_ux*lepton_ux + lepton_uy*lepton_uy + lepton_uz*lepton_uz);
100 amrex::ParticleReal const lepton_u = std::sqrt(lepton_u2);
101 amrex::ParticleReal const lepton_gamma = std::sqrt(1.0_prt + lepton_u2*inv_csq);
102 amrex::ParticleReal const lepton_beta = lepton_u / lepton_gamma * inv_c;
103 amrex::ParticleReal const lepton_nx = lepton_ux / lepton_u;
104 amrex::ParticleReal const lepton_ny = lepton_uy / lepton_u;
105 amrex::ParticleReal const lepton_nz = lepton_uz / lepton_u;
106 amrex::ParticleReal const photon_u = std::sqrt(photon_ux*photon_ux + photon_uy*photon_uy + photon_uz*photon_uz);
107 // - Perform the Lorentz transformation
108 amrex::ParticleReal photon_u_rest, photon_ux_rest, photon_uy_rest, photon_uz_rest;
109 LorentzTransformMomentum(
110 photon_u, photon_ux, photon_uy, photon_uz,
111 photon_u_rest, photon_ux_rest, photon_uy_rest, photon_uz_rest,
112 lepton_gamma, lepton_beta, lepton_nx, lepton_ny, lepton_nz);
113
114 // Find cos and sin of the spherical angle that represent
115 // the direction of the incoming photon in the rest frame
116 // TODO: Check if we could reuse code from the Coulomb scattering code.
117 amrex::ParticleReal const cos_theta = photon_uz_rest / photon_u_rest;
118 amrex::ParticleReal cos_phi = 0;
119 amrex::ParticleReal sin_phi = 0;
120 amrex::ParticleReal sin_theta = 0;
121 if (cos_theta*cos_theta < 1.0_prt) {
122 sin_theta = std::sqrt( 1.0_prt - cos_theta*cos_theta );
123 amrex::ParticleReal const inv_photon_rest_uxy = 1._prt / ( sin_theta * photon_u_rest );
124 cos_phi = photon_ux_rest * inv_photon_rest_uxy;
125 sin_phi = photon_uy_rest * inv_photon_rest_uxy;
126 } else {
127 sin_theta = 0._prt;
128 // Avoid division by 0; provide arbitrary direction
129 // for the phi angle (since theta is 0 or pi anyway)
130 cos_phi = 1.0_prt;
131 sin_phi = 0.0_prt;
132 }
133
134 // Draw scattering angle in the rest frame, from the
135 // Klein-Nishina cross-section (See Ozmutlu, E. N.
136 // "Sampling of Angular Distribution in Compton Scattering"
137 // Appl. Radiat. Isot. 43, 6, pp. 713-715 (1992))
138 amrex::ParticleReal const k = photon_u_rest * inv_c;
139 // By convention, in WarpX, the photon momentum u is normalized by the electron mass m_e, so k corresponds to p/(m_e*c)
140 amrex::ParticleReal const c0 = 2._prt * (2._prt*k*k + 2._prt*k + 1._prt) / amrex::Math::powi<3>(2._prt*k + 1._prt);
141 amrex::ParticleReal const b = (2._prt + c0) / (2._prt - c0);
142 amrex::ParticleReal const a = 2._prt*b - 1._prt;
143 // Use rejection method to draw x
144 bool reject = true;
145 amrex::ParticleReal x = 0;
146 while (reject) {
147 // - Draw x with an approximate probability distribution
148 amrex::ParticleReal const r1 = amrex::Random(engine);
149 x = b - (b + 1._prt)*std::pow(0.5_prt*c0, r1);
150 // - Calculate approximate probability distribution h
151 amrex::ParticleReal const h = a/(b-x);
152 // - Calculate expected (exact) probability distribution f
153 amrex::ParticleReal const factor = 1._prt + k*(1._prt-x);
154 amrex::ParticleReal const f = ( (1._prt+x*x)*factor + k*k*(1._prt-x)*(1._prt-x) )/(factor*factor*factor);
155 // - Keep x according to rejection rule
156 amrex::ParticleReal const r2 = amrex::Random(engine);
157 if (r2 < f/h) {
158 reject = false;
159 }
160 }
161
162 // Get scattered momentum in the rest frame
163 amrex::ParticleReal const new_photon_u_rest = photon_u_rest/( 1._prt + k*(1._prt-x) );
164 // - First in a system of axes aligned with the incoming photon
165 amrex::ParticleReal const cos_theta_s = x;
166 amrex::ParticleReal const sin_theta_s = std::sqrt( 1._prt - x*x );
167 amrex::ParticleReal const phi_s = 2._prt*MathConst::pi*amrex::Random(engine);
168 amrex::ParticleReal const cos_phi_s = std::cos( phi_s );
169 amrex::ParticleReal const sin_phi_s = std::sin( phi_s );
170 amrex::ParticleReal const new_photon_uX_rest = new_photon_u_rest * sin_theta_s*cos_phi_s;
171 amrex::ParticleReal const new_photon_uY_rest = new_photon_u_rest * sin_theta_s*sin_phi_s;
172 amrex::ParticleReal const new_photon_uZ_rest = new_photon_u_rest * cos_theta_s;
173 // - Then rotate it to the original system of axes
174 amrex::ParticleReal const new_photon_ux_rest = sin_theta * cos_phi * new_photon_uZ_rest
175 + cos_theta * cos_phi * new_photon_uX_rest
176 - sin_phi * new_photon_uY_rest;
177 amrex::ParticleReal const new_photon_uy_rest = sin_theta * sin_phi * new_photon_uZ_rest
178 + cos_theta * sin_phi * new_photon_uX_rest
179 + cos_phi * new_photon_uY_rest;
180 amrex::ParticleReal const new_photon_uz_rest = cos_theta * new_photon_uZ_rest
181 - sin_theta * new_photon_uX_rest;
182
183 // Transform the momentum of the scattered photon back to the lab frame
184 amrex::ParticleReal new_photon_u, new_photon_ux, new_photon_uy, new_photon_uz;
185 LorentzTransformMomentum(
186 new_photon_u_rest, new_photon_ux_rest, new_photon_uy_rest, new_photon_uz_rest,
187 new_photon_u, new_photon_ux, new_photon_uy, new_photon_uz,
188 lepton_gamma, lepton_beta, -lepton_nx, -lepton_ny, -lepton_nz);
189
190 // Fill momentum of product species (note that we actually
191 // create 4 products, 2 at the position of each incident particle)
192 // - Scattered photon
193 soa1_out.m_rdata[PIdx::ux][idx1_out_start] = new_photon_ux;
194 soa1_out.m_rdata[PIdx::uy][idx1_out_start] = new_photon_uy;
195 soa1_out.m_rdata[PIdx::uz][idx1_out_start] = new_photon_uz;
196 soa1_out.m_rdata[PIdx::ux][idx1_out_start + 1] = new_photon_ux;
197 soa1_out.m_rdata[PIdx::uy][idx1_out_start + 1] = new_photon_uy;
198 soa1_out.m_rdata[PIdx::uz][idx1_out_start + 1] = new_photon_uz;
199 // - Scattered electron (obtained by conserving momentum)
200 soa2_out.m_rdata[PIdx::ux][idx2_out_start] = lepton_ux - (new_photon_ux - photon_ux);
201 soa2_out.m_rdata[PIdx::uy][idx2_out_start] = lepton_uy - (new_photon_uy - photon_uy);
202 soa2_out.m_rdata[PIdx::uz][idx2_out_start] = lepton_uz - (new_photon_uz - photon_uz);
203 soa2_out.m_rdata[PIdx::ux][idx2_out_start + 1] = lepton_ux - (new_photon_ux - photon_ux);
204 soa2_out.m_rdata[PIdx::uy][idx2_out_start + 1] = lepton_uy - (new_photon_uy - photon_uy);
205 soa2_out.m_rdata[PIdx::uz][idx2_out_start + 1] = lepton_uz - (new_photon_uz - photon_uz);
206 }
207}
208
209#endif // LINEAR_COMPTON_INITIALIZE_MOMENTUM_H
#define AMREX_INLINE
#define AMREX_GPU_HOST_DEVICE
typename WarpXParticleContainer::ParticleTileType ParticleTileType
Definition ParticleUtils.H:22
DenseBins< ParticleTileDataType > ParticleBins
Definition ParticleUtils.cpp:30
typename WarpXParticleContainer::ParticleType ParticleType
Definition ParticleUtils.cpp:29
typename ParticleTileType::ParticleTileDataType ParticleTileDataType
Definition ParticleUtils.H:23
static constexpr auto c
vacuum speed of light [m/s]
Definition constant.H:44
static constexpr amrex::Real pi
ratio of a circle's circumference to its diameter
Definition constant.H:23
constexpr T powi(T x) noexcept
Real Random()
@ uz
Definition WarpXParticleContainer.H:70
@ uy
Definition WarpXParticleContainer.H:70
@ ux
Definition WarpXParticleContainer.H:70