File indexing completed on 2025-02-22 09:55:27
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/PdgParticle.hpp"
0012 #include "Acts/Material/Interactions.hpp"
0013
0014 #include <random>
0015
0016 namespace ActsFatras::detail {
0017
0018
0019
0020
0021
0022
0023
0024
0025 struct GeneralMixture {
0026
0027 bool log_include = true;
0028
0029 double genMixtureScalor = 1.;
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 template <typename generator_t>
0040 double operator()(generator_t &generator, const Acts::MaterialSlab &slab,
0041 Particle &particle) const {
0042 double theta = 0.0;
0043
0044 if (particle.absolutePdg() != Acts::PdgParticle::eElectron) {
0045
0046
0047
0048
0049
0050
0051 std::array<double, 4> scattering_params{};
0052
0053
0054
0055
0056 double mOverP = particle.mass() / particle.absoluteMomentum();
0057 double beta2Inv = 1 + mOverP * mOverP;
0058 double beta = 1 / std::sqrt(beta2Inv);
0059 double tInX0 = slab.thicknessInX0();
0060 double tob2 = tInX0 * beta2Inv;
0061 if (tob2 > 0.6 / std::pow(slab.material().Z(), 0.6)) {
0062
0063 if (tob2 > 10) {
0064 scattering_params = getGaussian(beta, particle.absoluteMomentum(),
0065 tInX0, genMixtureScalor);
0066 } else {
0067 scattering_params =
0068 getGaussmix(beta, particle.absoluteMomentum(), tInX0,
0069 slab.material().Z(), genMixtureScalor);
0070 }
0071
0072 theta = gaussmix(generator, scattering_params);
0073 } else {
0074
0075 auto scattering_params_sg =
0076 getSemigauss(beta, particle.absoluteMomentum(), tInX0,
0077 slab.material().Z(), genMixtureScalor);
0078
0079 theta = semigauss(generator, scattering_params_sg);
0080 }
0081 } else {
0082
0083
0084 const auto theta0 = Acts::computeMultipleScatteringTheta0(
0085 slab, particle.absolutePdg(), particle.mass(), particle.qOverP(),
0086 particle.absoluteCharge());
0087 theta = std::normal_distribution<double>(0.0, theta0)(generator);
0088 }
0089
0090 return M_SQRT2 * theta;
0091 }
0092
0093
0094
0095 std::array<double, 4> getGaussian(double beta, double p, double tInX0,
0096 double scale) const {
0097 std::array<double, 4> scattering_params{};
0098
0099 scattering_params[0] = 15. / beta / p * std::sqrt(tInX0) * scale;
0100 scattering_params[1] = 1.0;
0101 scattering_params[2] = 1.0;
0102 scattering_params[3] = 0.5;
0103 return scattering_params;
0104 }
0105
0106 std::array<double, 4> getGaussmix(double beta, double p, double tInX0,
0107 double Z, double scale) const {
0108 std::array<double, 4> scattering_params{};
0109 scattering_params[0] = 15. / beta / p * std::sqrt(tInX0) *
0110 scale;
0111 double d1 = std::log(tInX0 / (beta * beta));
0112 double d2 = std::log(std::pow(Z, 2.0 / 3.0) * tInX0 / (beta * beta));
0113 double epsi = 0;
0114 double var1 = (-1.843e-3 * d1 + 3.347e-2) * d1 + 8.471e-1;
0115
0116 if (d2 < 0.5) {
0117 epsi = (6.096e-4 * d2 + 6.348e-3) * d2 + 4.841e-2;
0118 } else {
0119 epsi = (-5.729e-3 * d2 + 1.106e-1) * d2 - 1.908e-2;
0120 }
0121 scattering_params[1] = var1;
0122 scattering_params[2] = (1 - (1 - epsi) * var1) / epsi;
0123 scattering_params[3] = epsi;
0124 return scattering_params;
0125 }
0126
0127 std::array<double, 6> getSemigauss(double beta, double p, double tInX0,
0128 double Z, double scale) const {
0129 std::array<double, 6> scattering_params{};
0130 double N = tInX0 * 1.587E7 * std::pow(Z, 1.0 / 3.0) / (beta * beta) /
0131 (Z + 1) / std::log(287 / std::sqrt(Z));
0132 scattering_params[4] = 15. / beta / p * std::sqrt(tInX0) *
0133 scale;
0134 double rho = 41000 / std::pow(Z, 2.0 / 3.0);
0135 double b = rho / std::sqrt(N * (std::log(rho) - 0.5));
0136 double n = std::pow(Z, 0.1) * std::log(N);
0137 double var1 = (5.783E-4 * n + 3.803E-2) * n + 1.827E-1;
0138 double a =
0139 (((-4.590E-5 * n + 1.330E-3) * n - 1.355E-2) * n + 9.828E-2) * n +
0140 2.822E-1;
0141 double epsi = (1 - var1) / (a * a * (std::log(b / a) - 0.5) - var1);
0142 scattering_params[3] =
0143 (epsi > 0) ? epsi : 0.0;
0144 scattering_params[0] = a;
0145 scattering_params[1] = b;
0146 scattering_params[2] = var1;
0147 scattering_params[5] = N;
0148 return scattering_params;
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 template <typename generator_t>
0160 double gaussmix(generator_t &generator,
0161 const std::array<double, 4> &scattering_params) const {
0162 std::uniform_real_distribution<double> udist(0.0, 1.0);
0163 double sigma_tot = scattering_params[0];
0164 double var1 = scattering_params[1];
0165 double var2 = scattering_params[2];
0166 double epsi = scattering_params[3];
0167 bool ind = udist(generator) > epsi;
0168 double u = udist(generator);
0169 if (ind) {
0170 return std::sqrt(var1) * std::sqrt(-2 * std::log(u)) * sigma_tot;
0171 } else {
0172 return std::sqrt(var2) * std::sqrt(-2 * std::log(u)) * sigma_tot;
0173 }
0174 }
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 template <typename generator_t>
0185 double semigauss(generator_t &generator,
0186 const std::array<double, 6> &scattering_params) const {
0187 std::uniform_real_distribution<double> udist(0.0, 1.0);
0188 double a = scattering_params[0];
0189 double b = scattering_params[1];
0190 double var1 = scattering_params[2];
0191 double epsi = scattering_params[3];
0192 double sigma_tot = scattering_params[4];
0193 bool ind = udist(generator) > epsi;
0194 double u = udist(generator);
0195 if (ind) {
0196 return std::sqrt(var1) * std::sqrt(-2 * std::log(u)) * sigma_tot;
0197 } else {
0198 return a * b * std::sqrt((1 - u) / (u * b * b + a * a)) * sigma_tot;
0199 }
0200 }
0201 };
0202
0203 }