File indexing completed on 2025-01-19 09:23:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/TrackFitting/detail/GsfUtils.hpp"
0013
0014 #include <algorithm>
0015 #include <array>
0016 #include <cassert>
0017 #include <cmath>
0018 #include <cstddef>
0019 #include <fstream>
0020 #include <mutex>
0021 #include <random>
0022 #include <stdexcept>
0023 #include <string>
0024 #include <tuple>
0025
0026 #include <boost/container/static_vector.hpp>
0027
0028 namespace Acts {
0029
0030 namespace detail {
0031
0032 struct GaussianComponent {
0033 ActsScalar weight = 0.0;
0034 ActsScalar mean = 0.0;
0035 ActsScalar var = 0.0;
0036 };
0037
0038
0039
0040 inline void transformComponent(const GaussianComponent &cmp,
0041 double &transformed_weight,
0042 double &transformed_mean,
0043 double &transformed_var) {
0044 const auto &[weight, mean, var] = cmp;
0045
0046 transformed_weight = std::log(weight) - std::log(1 - weight);
0047 transformed_mean = std::log(mean) - std::log(1 - mean);
0048 transformed_var = std::log(var);
0049 }
0050
0051
0052
0053 inline auto inverseTransformComponent(double transformed_weight,
0054 double transformed_mean,
0055 double transformed_var) {
0056 GaussianComponent cmp;
0057 cmp.weight = 1. / (1 + std::exp(-transformed_weight));
0058 cmp.mean = 1. / (1 + std::exp(-transformed_mean));
0059 cmp.var = std::exp(transformed_var);
0060
0061 return cmp;
0062 }
0063
0064 }
0065
0066
0067
0068
0069 struct BetheHeitlerApproxSingleCmp {
0070
0071 constexpr auto numComponents() const { return 1; }
0072
0073
0074
0075 constexpr bool validXOverX0(ActsScalar x) const {
0076 return x < 0.002;
0077 ;
0078 }
0079
0080
0081
0082
0083
0084 static auto mixture(const ActsScalar x) {
0085 std::array<detail::GaussianComponent, 1> ret{};
0086
0087 ret[0].weight = 1.0;
0088
0089 const double c = x / std::log(2);
0090 ret[0].mean = std::pow(2, -c);
0091 ret[0].var = std::pow(3, -c) - std::pow(4, -c);
0092
0093 return ret;
0094 }
0095 };
0096
0097
0098
0099
0100
0101
0102
0103
0104 template <int NComponents, int PolyDegree>
0105 class AtlasBetheHeitlerApprox {
0106 static_assert(NComponents > 0);
0107 static_assert(PolyDegree > 0);
0108
0109 public:
0110 struct PolyData {
0111 std::array<ActsScalar, PolyDegree + 1> weightCoeffs;
0112 std::array<ActsScalar, PolyDegree + 1> meanCoeffs;
0113 std::array<ActsScalar, PolyDegree + 1> varCoeffs;
0114 };
0115
0116 using Data = std::array<PolyData, NComponents>;
0117
0118 private:
0119 Data m_lowData;
0120 Data m_highData;
0121 bool m_lowTransform;
0122 bool m_highTransform;
0123
0124 constexpr static double m_noChangeLimit = 0.0001;
0125 constexpr static double m_singleGaussianLimit = 0.002;
0126 double m_lowLimit = 0.10;
0127 double m_highLimit = 0.20;
0128
0129 public:
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 constexpr AtlasBetheHeitlerApprox(const Data &lowData, const Data &highData,
0142 bool lowTransform, bool highTransform,
0143 double lowLimit = 0.1,
0144 double highLimit = 0.2)
0145 : m_lowData(lowData),
0146 m_highData(highData),
0147 m_lowTransform(lowTransform),
0148 m_highTransform(highTransform),
0149 m_lowLimit(lowLimit),
0150 m_highLimit(highLimit) {}
0151
0152
0153 constexpr auto numComponents() const { return NComponents; }
0154
0155
0156
0157
0158 constexpr bool validXOverX0(ActsScalar x) const { return x < m_highLimit; }
0159
0160
0161
0162
0163
0164 auto mixture(ActsScalar x) const {
0165 using Array =
0166 boost::container::static_vector<detail::GaussianComponent, NComponents>;
0167
0168 auto poly = [](ActsScalar xx,
0169 const std::array<ActsScalar, PolyDegree + 1> &coeffs) {
0170 ActsScalar sum{0.};
0171 for (const auto c : coeffs) {
0172 sum = xx * sum + c;
0173 }
0174 assert((std::isfinite(sum) && "polynom result not finite"));
0175 return sum;
0176 };
0177
0178
0179 auto make_mixture = [&](const Data &data, double xx, bool transform) {
0180
0181 Array ret(NComponents);
0182 ActsScalar weight_sum = 0;
0183 for (int i = 0; i < NComponents; ++i) {
0184
0185
0186 if (transform) {
0187 ret[i] = detail::inverseTransformComponent(
0188 poly(xx, data[i].weightCoeffs), poly(xx, data[i].meanCoeffs),
0189 poly(xx, data[i].varCoeffs));
0190 } else {
0191 ret[i].weight = poly(xx, data[i].weightCoeffs);
0192 ret[i].mean = poly(xx, data[i].meanCoeffs);
0193 ret[i].var = poly(xx, data[i].varCoeffs);
0194 }
0195
0196 weight_sum += ret[i].weight;
0197 }
0198
0199 for (int i = 0; i < NComponents; ++i) {
0200 ret[i].weight /= weight_sum;
0201 }
0202
0203 return ret;
0204 };
0205
0206
0207 if (x < m_noChangeLimit) {
0208 Array ret(1);
0209
0210 ret[0].weight = 1.0;
0211 ret[0].mean = 1.0;
0212 ret[0].var = 0.0;
0213
0214 return ret;
0215 }
0216
0217 if (x < m_singleGaussianLimit) {
0218 Array ret(1);
0219 ret[0] = BetheHeitlerApproxSingleCmp::mixture(x)[0];
0220 return ret;
0221 }
0222
0223 if (x < m_lowLimit) {
0224 return make_mixture(m_lowData, x, m_lowTransform);
0225 }
0226
0227
0228 const auto high_x = std::min(m_highLimit, x);
0229 return make_mixture(m_highData, high_x, m_highTransform);
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 static auto loadFromFiles(const std::string &low_parameters_path,
0242 const std::string &high_parameters_path,
0243 double lowLimit = 0.1, double highLimit = 0.2) {
0244 auto read_file = [](const std::string &filepath) {
0245 std::ifstream file(filepath);
0246
0247 if (!file) {
0248 throw std::invalid_argument("Could not open '" + filepath + "'");
0249 }
0250
0251 std::size_t n_cmps = 0, degree = 0;
0252 bool transform_code = false;
0253
0254 file >> n_cmps >> degree >> transform_code;
0255
0256 if (NComponents != n_cmps) {
0257 throw std::invalid_argument("Wrong number of components in '" +
0258 filepath + "'");
0259 }
0260
0261 if (PolyDegree != degree) {
0262 throw std::invalid_argument("Wrong polynom order in '" + filepath +
0263 "'");
0264 }
0265
0266 Data data;
0267
0268 for (auto &cmp : data) {
0269 for (auto &coeff : cmp.weightCoeffs) {
0270 file >> coeff;
0271 }
0272 for (auto &coeff : cmp.meanCoeffs) {
0273 file >> coeff;
0274 }
0275 for (auto &coeff : cmp.varCoeffs) {
0276 file >> coeff;
0277 }
0278 }
0279
0280 return std::make_tuple(data, transform_code);
0281 };
0282
0283 const auto [lowData, lowTransform] = read_file(low_parameters_path);
0284 const auto [highData, highTransform] = read_file(high_parameters_path);
0285
0286 return AtlasBetheHeitlerApprox(lowData, highData, lowTransform,
0287 highTransform, lowLimit, highLimit);
0288 }
0289 };
0290
0291
0292
0293
0294
0295 AtlasBetheHeitlerApprox<6, 5> makeDefaultBetheHeitlerApprox();
0296
0297 }