File indexing completed on 2026-08-03 08:21:54
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/TrackFitting/BetheHeitlerApprox.hpp"
0010
0011 #include "Acts/Utilities/RangeXD.hpp"
0012
0013 #include <algorithm>
0014 #include <stdexcept>
0015
0016 namespace Acts {
0017
0018 PolynomialBetheHeitlerApprox::PolynomialBetheHeitlerApprox(
0019 std::vector<RangeData> ranges, bool clampToRange, double noChangeLimit,
0020 double singleGaussianLimit)
0021 : m_ranges(std::move(ranges)),
0022 m_clampToRange(clampToRange),
0023 m_noChangeLimit(noChangeLimit),
0024 m_singleGaussianLimit(singleGaussianLimit) {
0025 if (m_ranges.empty()) {
0026 throw std::invalid_argument("At least one range is required");
0027 }
0028
0029
0030 std::ranges::sort(m_ranges, {}, [](const auto &r) { return r.range.min(); });
0031
0032
0033 for (std::size_t i = 1; i < m_ranges.size(); ++i) {
0034 if (m_ranges[i - 1].range && m_ranges[i].range) {
0035 throw std::invalid_argument(
0036 "Overlapping ranges detected. Ranges must be non-overlapping.");
0037 }
0038 }
0039 }
0040
0041 std::span<PolynomialBetheHeitlerApprox::Component>
0042 PolynomialBetheHeitlerApprox::mixture(
0043 double xOverX0, const std::span<Component> mixture) const {
0044 if (m_clampToRange) {
0045 xOverX0 = std::clamp(xOverX0, 0.0, rangeMax());
0046 }
0047
0048
0049 const auto poly = [](const double xx, const std::span<const double> coeffs) {
0050 double sum{0.};
0051 for (const auto c : coeffs) {
0052 sum = xx * sum + c;
0053 }
0054 return sum;
0055 };
0056
0057
0058 const auto make_mixture = [&](const Data &data, double xx,
0059 bool transform) -> std::span<Component> {
0060
0061 double weight_sum = 0;
0062 for (std::size_t i = 0; i < data.size(); ++i) {
0063
0064
0065 if (transform) {
0066 mixture[i] = detail::inverseTransformComponent(
0067 {poly(xx, data[i].weightCoeffs), poly(xx, data[i].meanCoeffs),
0068 poly(xx, data[i].varCoeffs)});
0069 } else {
0070 mixture[i].weight = poly(xx, data[i].weightCoeffs);
0071 mixture[i].mean = poly(xx, data[i].meanCoeffs);
0072 mixture[i].var = poly(xx, data[i].varCoeffs);
0073 }
0074
0075 weight_sum += mixture[i].weight;
0076 }
0077
0078 for (std::size_t i = 0; i < data.size(); ++i) {
0079 mixture[i].weight /= weight_sum;
0080 }
0081
0082 return {mixture.data(), data.size()};
0083 };
0084
0085
0086 if (xOverX0 < m_noChangeLimit) {
0087 mixture[0].weight = 1.0;
0088 mixture[0].mean = 1.0;
0089 mixture[0].var = 0.0;
0090
0091 return {mixture.data(), 1};
0092 }
0093
0094
0095 if (xOverX0 < m_singleGaussianLimit) {
0096 BetheHeitlerApproxSingleCmp().mixture(xOverX0, mixture);
0097 return {mixture.data(), 1};
0098 }
0099
0100
0101 for (const auto &[range, data, transform] : m_ranges) {
0102 if (range.contains(xOverX0)) {
0103 return make_mixture(data, xOverX0, transform);
0104 }
0105 }
0106
0107
0108
0109 const auto &[lastRange, lastData, lastTransform] = m_ranges.back();
0110 return make_mixture(lastData, lastRange.max(), lastTransform);
0111 }
0112
0113 PolynomialBetheHeitlerApprox makeDefaultBetheHeitlerApprox(bool clampToRange) {
0114
0115
0116 static PolynomialBetheHeitlerApprox::Data cdf_cmps6_order5_data = {{
0117
0118 {
0119 {{3.74397e+004,-1.95241e+004, 3.51047e+003,-2.54377e+002, 1.81080e+001,-3.57643e+000}},
0120 {{3.56728e+004,-1.78603e+004, 2.81521e+003,-8.93555e+001,-1.14015e+001, 2.55769e-001}},
0121 {{3.73938e+004,-1.92800e+004, 3.21580e+003,-1.46203e+002,-5.65392e+000,-2.78008e+000}}
0122 },
0123
0124 {
0125 {{-4.14035e+004, 2.31883e+004,-4.37145e+003, 2.44289e+002, 1.13098e+001,-3.21230e+000}},
0126 {{-2.06936e+003, 2.65334e+003,-1.01413e+003, 1.78338e+002,-1.85556e+001, 1.91430e+000}},
0127 {{-5.19068e+004, 2.55327e+004,-4.22147e+003, 1.90227e+002, 9.34602e+000,-4.80961e+000}}
0128 },
0129
0130 {
0131 {{2.52200e+003,-4.86348e+003, 2.11942e+003,-3.84534e+002, 2.94503e+001,-2.83310e+000}},
0132 {{1.80405e+003,-1.93347e+003, 6.27196e+002,-4.32429e+001,-1.43533e+001, 3.58782e+000}},
0133 {{-4.61617e+004, 1.78221e+004,-1.95746e+003,-8.80646e+001, 3.43153e+001,-7.57830e+000}}
0134 },
0135
0136 {
0137 {{4.94537e+003,-2.08737e+003, 1.78089e+002, 2.29879e+001,-5.52783e+000,-1.86800e+000}},
0138 {{4.60220e+003,-1.62269e+003,-1.57552e+002, 2.01796e+002,-5.01636e+001, 6.47438e+000}},
0139 {{-9.50373e+004, 4.05517e+004,-5.62596e+003, 4.58534e+001, 6.70479e+001,-1.22430e+001}}
0140 },
0141
0142 {
0143 {{-1.04129e+003, 1.15222e+002,-2.70356e+001, 3.18611e+001,-7.78800e+000,-1.50242e+000}},
0144 {{-2.71361e+004, 2.00625e+004,-6.19444e+003, 1.10061e+003,-1.29354e+002, 1.08289e+001}},
0145 {{3.15252e+004,-3.31508e+004, 1.20371e+004,-2.23822e+003, 2.44396e+002,-2.09130e+001}}
0146 },
0147
0148 {
0149 {{1.27751e+004,-6.79813e+003, 1.24650e+003,-8.20622e+001,-2.33476e+000, 2.46459e-001}},
0150 {{3.64336e+005,-2.08457e+005, 4.33028e+004,-3.67825e+003, 4.22914e+001, 1.42701e+001}},
0151 {{-1.79298e+006, 1.01843e+006,-2.10037e+005, 1.82222e+004,-4.33573e+002,-2.72725e+001}}
0152 },
0153 }};
0154
0155
0156 std::vector<PolynomialBetheHeitlerApprox::RangeData> ranges = {
0157 {Range1D<double>{0.0, 0.2}, cdf_cmps6_order5_data, true}};
0158
0159 return PolynomialBetheHeitlerApprox(std::move(ranges), clampToRange, 0.0001,
0160 0.002);
0161 }
0162
0163 }