ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
interaction.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s)
12#include "detray/definitions/algebra.hpp"
13#include "detray/definitions/detail/qualifiers.hpp"
14#include "detray/definitions/math.hpp"
15#include "detray/definitions/pdg_particle.hpp"
16#include "detray/definitions/units.hpp"
17#include "detray/material/detail/relativistic_quantities.hpp"
18
19namespace detray {
20
22template <concepts::scalar scalar_t>
25 using scalar_type = scalar_t;
27 using relativistic_quantities = detail::relativistic_quantities<scalar_type>;
28
29 // @returns the total stopping power (<-dE/dx>)
35 DETRAY_HOST_DEVICE scalar_type
38 const relativistic_quantities& rq) const {
39 scalar_type stopping_power{0.f};
40
41 // Inelastic collisions with atomic electrons
42 stopping_power += compute_bethe_bloch(mat, ptc, rq);
43
44 // Radiative loss
45 stopping_power += compute_bremsstrahlung(mat, ptc, rq);
46
47 return stopping_power;
48 }
49
54 DETRAY_HOST_DEVICE scalar_type
56 const pdg_particle<scalar_type>& /*ptc*/,
57 const relativistic_quantities& rq) const {
58 const scalar_type eps_per_length{rq.compute_epsilon_per_length(mat)};
59 if (eps_per_length <= 0.f) {
60 return 0.f;
61 }
62
63 const scalar_type dhalf{rq.compute_delta_half(mat)};
64 const scalar_type A = rq.compute_bethe_bloch_log_term(mat);
65 const scalar_type running{A - rq.m_beta2 - dhalf};
66 return 2.f * eps_per_length * running;
67 }
68
69 // Function to calculate the Bremsstrahlung energy loss of electron based on
70 // Rossi's approximation.
71 // For more rigorous calculation, check "G4eBremsstrahlungRelModel.cc" of
72 // Geant4 library. The Fig 34.13 of PDG 2024 shows the difference between
73 // the approximated and precise calculation.
80 DETRAY_HOST_DEVICE scalar_type
83 const relativistic_quantities& rq) const {
84 scalar_type stopping_power{0.f};
85
86 // Only consider electrons and positrons at the moment
87 // For middle-heavy particles muons, the bremss is negligibe
88 //
89 // Also, over 10 MeV, positron and electron bremss might be similar.
90 // In ICRU 37, it is written that "In our tabulations, the radiative
91 // stopping power for positrons has been assumed to be the same as that
92 // for electrons, which is a good approximation at energies above, say,
93 // 10 MeV. However, it should be mentioned that exploratory calculations
94 // by Feng et at. (1981), employing the same method as that previously
95 // used by them for electrons, indicate significant differences between
96 // positrons and electrons in regard to the differential bremsstrahlung
97 // cross sections in oxygen and uranium at 500, 50, and 10 keV"
98 if (ptc.pdg_num() == electron<scalar_type>().pdg_num() ||
100 // Stopping power ~ E/X (B. B. Rossi, High-energy particles,1952)
101 // This approximation gets poor in low energy below 10 MeV
102 stopping_power = rq.m_gamma * ptc.mass() / mat.X0();
103 }
104
105 return stopping_power;
106 }
107
115 DETRAY_HOST_DEVICE scalar_type
117 const pdg_particle<scalar_type>& ptc,
118 const relativistic_quantities& rq) const {
119 scalar_type derivative{0.f};
120
121 // Inelastic collisions with atomic electrons
122 derivative += derive_bethe_bloch(mat, ptc, rq);
123
124 // Radiative loss
125 derivative += derive_bremsstrahlung(mat, ptc, rq);
126
127 return derivative;
128 }
129
137 DETRAY_HOST_DEVICE scalar_type
139 const pdg_particle<scalar_type>& ptc,
140 const relativistic_quantities& rq) const {
141 const scalar_type bethe_stopping_power = compute_bethe_bloch(mat, ptc, rq);
142
143 // (K/2) * (Z/A) * z^2 / beta^2 * density
144 const scalar_type eps_per_length{rq.compute_epsilon_per_length(mat)};
145 if (eps_per_length <= 0.f) {
146 return 0.f;
147 }
148
149 /*-----------------------------------------------------------------------
150 * Calculation of d(-dE/dx)/dqop
151 *
152 * d(-dE/dx)/dqop = 2/(qop * gamma^2) * (-dE/dx)
153 * + 2 * (eps/x) * [dA/dqop - dB/dqop - dC/dqop]
154 *
155 * where
156 * A = 1/2 ln ( 2m_e c^2 beta^2 gamma^2 W_max/ I^2)
157 * B = beta^2
158 * C = delta/2
159 *
160 * dA/dqop = -1 / (2 * qop) * [4 - W_max/ (gamma M c^2) ]
161 * dB/dqop = -2 * beta^2/(qop gamma^2)
162 *
163 * dC/dqop = 1/2*(-2/qop) if (x>x_1)
164 * = 1/2*(-2/qop + ak/(qop ln10)*(x_1 - x)^(k-1)) if (x_0<x<x_1)
165 * = 0 if (x<x_0) (for nonconductors)
166 ------------------------------------------------------------------------*/
167
168 const scalar_type first_term =
169 2.f / (rq.m_qOverP * rq.m_gamma2) * bethe_stopping_power;
170
171 const scalar_type dAdqop = rq.derive_bethe_bloch_log_term();
172 const scalar_type dBdqop = rq.derive_beta2();
173 const scalar_type dCdqop = rq.derive_delta_half(mat);
174
175 const scalar_type second_term =
176 2.f * eps_per_length * (dAdqop - dBdqop - dCdqop);
177
178 return first_term + second_term;
179 }
180
186 DETRAY_HOST_DEVICE scalar_type
188 const pdg_particle<scalar_type>& ptc,
189 const relativistic_quantities& rq) const {
190 scalar_type derivative{0.f};
191
192 if (ptc.pdg_num() == electron<scalar_type>().pdg_num() ||
194 // Stopping power ~ E/X = gamma * m/X
195 // Derivative = dgamma/dqop * m/X = -beta^2 gamma/qop * m/X
196 // (Eq (D.5) of arXiv:2403.16720)
197 derivative =
198 -rq.m_beta2 * rq.m_gamma / rq.m_qOverP * ptc.mass() / mat.X0();
199 }
200
201 return derivative;
202 }
203
211 const scalar_type path_segment, const detray::material<scalar_type>& mat,
212 const pdg_particle<scalar_type>& ptc,
213 const relativistic_quantities& rq) const {
214 return path_segment * compute_bethe_bloch(mat, ptc, rq);
215 }
216
223 const scalar_type path_segment, const material<scalar_type>& mat,
224 const pdg_particle<scalar_type>& /*ptc*/,
225 const relativistic_quantities& rq) const {
226 const scalar_type I{mat.mean_excitation_energy()};
227 const scalar_type eps{rq.compute_epsilon(mat, path_segment)};
228
229 if (eps <= 0.f) {
230 return 0.f;
231 }
232
233 const scalar_type dhalf{rq.compute_delta_half(mat)};
234 const scalar_type t{rq.compute_mass_term(constant<scalar_type>::m_e)};
235 // uses RPP2018 eq. 33.11
236 const scalar_type running{math::log(t / I) + math::log(eps / I) + 0.2f -
237 rq.m_beta2 - 2.f * dhalf};
238 return eps * running;
239 }
240
247 const scalar_type path_segment, const material<scalar_type>& mat,
248 const pdg_particle<scalar_type>& /*ptc*/,
249 const relativistic_quantities& rq) const {
250 // the Landau-Vavilov fwhm is 4*eps (see RPP2018 fig. 33.7)
251 return 4.f * rq.compute_epsilon(mat, path_segment);
252 }
253
261 const scalar_type path_segment, const material<scalar_type>& mat,
262 const pdg_particle<scalar_type>& ptc,
263 const relativistic_quantities& rq) const {
264 const scalar_type fwhm{
265 compute_energy_loss_landau_fwhm(path_segment, mat, ptc, rq)};
266
267 return convert_landau_fwhm_to_gaussian_sigma(fwhm);
268 }
269
276 template <typename material_t>
278 const scalar_type path_segment, const material_t& mat,
279 const pdg_particle<scalar_type>& ptc,
280 const relativistic_quantities& rq) const {
281 const scalar_type sigmaE{
282 compute_energy_loss_landau_sigma(path_segment, mat, ptc, rq)};
283
284 // var(q/p) = (d(q/p)/dE)² * var(E)
285 // d(q/p)/dE = d/dE (q/sqrt(E²-m²))
286 // = q * -(1/2) * 1/p³ * 2E
287 // var(q/p) = (q/p)^4 * (q/beta)² * (1/q)^4 * var(E)
288 // = -q/p² E/p = -(q/p)² * 1/(q*beta) = -(q/p)² * (q/beta)
289 // / q² = (1/p)^4 * (q/beta)² * var(E)
290 // do not need to care about the sign since it is only used squared
291 const scalar_type pInv{rq.m_qOverP / ptc.charge()};
292 return math::sqrt(rq.m_q2OverBeta2) * pInv * pInv * sigmaE;
293 }
294
301 const scalar_type xOverX0, const pdg_particle<scalar_type>& ptc,
302 const relativistic_quantities& rq) const {
303 // 1/p = q/(pq) = (q/p)/q
304 const scalar_type momentumInv{math::fabs(rq.m_qOverP / ptc.charge())};
305 // q²/beta²; a smart compiler should be able to remove the unused
306 // computations
307
308 // if electron or positron
309 if ((ptc.pdg_num() == 11) || (ptc.pdg_num() == -11)) {
310 //@todo (Beomki): Not sure if we need this function. At least we
311 // need to find the reference for this equation
312 return theta0RossiGreisen(xOverX0, momentumInv, rq.m_q2OverBeta2);
313 } else {
314 return theta0Highland(xOverX0, momentumInv, rq.m_q2OverBeta2);
315 }
316 }
317
318 private:
322 DETRAY_HOST_DEVICE scalar_type
323 theta0Highland(const scalar_type xOverX0, const scalar_type momentumInv,
324 const scalar_type q2OverBeta2) const {
325 if (xOverX0 <= 0.f) {
326 return 0.f;
327 }
328
329 // RPP2018 eq. 33.15 (treats beta and q² consistently)
330 const scalar_type t{math::sqrt(xOverX0 * q2OverBeta2)};
331 // log((x/X0) * (q²/beta²)) = log((sqrt(x/X0) * (q/beta))²)
332 // = 2 * log(sqrt(x/X0) * (q/beta))
333 return 13.6f * unit<scalar_type>::MeV * momentumInv * t *
334 (1.0f + 0.038f * 2.f * math::log(t));
335 }
336
338 DETRAY_HOST_DEVICE scalar_type
339 theta0RossiGreisen(const scalar_type xOverX0, const scalar_type momentumInv,
340 const scalar_type q2OverBeta2) const {
341 if (xOverX0 <= 0.f) {
342 return 0.f;
343 }
344
345 // TODO add source paper/ resource
346 const scalar_type t{math::sqrt(xOverX0 * q2OverBeta2)};
347 return 17.5f * unit<scalar_type>::MeV * momentumInv * t *
348 (1.0f + 0.125f * math::log10(10.0f * xOverX0));
349 }
350
360 DETRAY_HOST_DEVICE scalar_type
361 convert_landau_fwhm_to_gaussian_sigma(const scalar_type fwhm) const {
362 return 0.5f * constant<scalar_type>::inv_sqrt2 * fwhm /
363 math::sqrt(constant<scalar_type>::ln2);
364 }
365};
366
367} // namespace detray
Detray include(s).
Definition array_operators.hpp:18
static constexpr scalar_t inv_sqrt2
1/(√2)
Definition units.hpp:151
static constexpr scalar_t m_e
Electron rest energy expressed in the internal energy unit.
Definition units.hpp:168
static constexpr scalar_t ln2
Natural logarithm of 2.
Definition units.hpp:131
Electron hypothesis.
Definition pdg_particle.hpp:103
Computes energy loss and multiple scattering in detector material.
Definition interaction.hpp:23
detail::relativistic_quantities< scalar_type > relativistic_quantities
Cached particle kinematics used by the interaction formulas.
Definition interaction.hpp:27
scalar_type compute_energy_loss_landau_fwhm(const scalar_type path_segment, const material< scalar_type > &mat, const pdg_particle< scalar_type > &, const relativistic_quantities &rq) const
Compute the Landau energy-loss distribution full width at half maximum.
Definition interaction.hpp:246
scalar_type compute_energy_loss_landau(const scalar_type path_segment, const material< scalar_type > &mat, const pdg_particle< scalar_type > &, const relativistic_quantities &rq) const
Compute the most-probable energy loss using the Landau approximation.
Definition interaction.hpp:222
scalar_type derive_bethe_bloch(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Differentiate the Bethe–Bloch stopping power with respect to q/p.
Definition interaction.hpp:138
scalar_type derive_bremsstrahlung(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Differentiate the bremsstrahlung stopping power with respect to q/p.
Definition interaction.hpp:187
scalar_type compute_multiple_scattering_theta0(const scalar_type xOverX0, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Estimate the projected multiple-scattering angle for a material thickness.
Definition interaction.hpp:300
scalar_type compute_energy_loss_bethe_bloch(const scalar_type path_segment, const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Compute the collisional energy loss over a path segment.
Definition interaction.hpp:210
scalar_type compute_energy_loss_landau_sigma_QOverP(const scalar_type path_segment, const material_t &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Convert energy-loss sigma to a q/p uncertainty.
Definition interaction.hpp:277
scalar_t scalar_type
Scalar type used by the interaction calculations.
Definition interaction.hpp:25
scalar_type compute_bremsstrahlung(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Estimate electron or positron radiative stopping power using Rossi’s approximation.
Definition interaction.hpp:81
scalar_type compute_stopping_power(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Sum collisional and radiative stopping-power contributions.
Definition interaction.hpp:36
scalar_type derive_stopping_power(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Differentiate the total stopping power with respect to q/p.
Definition interaction.hpp:116
scalar_type compute_energy_loss_landau_sigma(const scalar_type path_segment, const material< scalar_type > &mat, const pdg_particle< scalar_type > &ptc, const relativistic_quantities &rq) const
Convert the Landau width to a Gaussian-equivalent energy-loss sigma.
Definition interaction.hpp:260
scalar_type compute_bethe_bloch(const detray::material< scalar_type > &mat, const pdg_particle< scalar_type > &, const relativistic_quantities &rq) const
Compute the collisional stopping power from the Bethe–Bloch expression.
Definition interaction.hpp:55
Material composition properties and density data used by interactions.
Definition material.hpp:36
scalar_type mean_excitation_energy() const
Definition material.hpp:154
constexpr scalar_type X0() const
Definition material.hpp:118
Particle hypothesis identified by PDG number, mass, and electric charge.
Definition pdg_particle.hpp:24
constexpr std::int32_t pdg_num() const
Definition pdg_particle.hpp:41
constexpr scalar_type mass() const
Definition pdg_particle.hpp:45
constexpr scalar_type charge() const
Definition pdg_particle.hpp:49
Positron hypothesis.
Definition pdg_particle.hpp:106
static constexpr scalar_t MeV
Megaelectronvolt expressed in GeV.
Definition units.hpp:79