File indexing completed on 2026-04-09 07:46:09
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/TrackFitting/detail/GsfUtils.hpp"
0010
0011 #include "Acts/EventData/MeasurementHelpers.hpp"
0012 #include "Acts/EventData/ParticleHypothesis.hpp"
0013 #include "Acts/EventData/SubspaceHelpers.hpp"
0014 #include "Acts/EventData/Types.hpp"
0015 #include "Acts/Material/ISurfaceMaterial.hpp"
0016 #include "Acts/Material/MaterialSlab.hpp"
0017
0018 #include <cstddef>
0019 #include <cstdint>
0020 #include <span>
0021
0022 namespace Acts {
0023
0024 double detail::Gsf::calculateDeterminant(
0025 const double *fullCalibratedCovariance,
0026 TrackStateTraits<kMeasurementSizeMax, true>::Covariance predictedCovariance,
0027 BoundSubspaceIndices projector, unsigned int calibratedSize) {
0028 return visit_measurement(calibratedSize, [&](auto N) {
0029 constexpr std::size_t kMeasurementSize = decltype(N)::value;
0030 std::span<const std::uint8_t, kMeasurementSize> validSubspaceIndices(
0031 projector.begin(), projector.begin() + kMeasurementSize);
0032 FixedBoundSubspaceHelper<kMeasurementSize> subspaceHelper(
0033 validSubspaceIndices);
0034
0035 typename Acts::TrackStateTraits<
0036 kMeasurementSize, true>::CalibratedCovariance calibratedCovariance{
0037 fullCalibratedCovariance};
0038
0039 const auto H = subspaceHelper.projector();
0040
0041 return (H * predictedCovariance * H.transpose() + calibratedCovariance)
0042 .determinant();
0043 });
0044 }
0045
0046 void detail::Gsf::removeLowWeightComponents(std::vector<GsfComponent> &cmps,
0047 double weightCutoff) {
0048 auto proj = [](auto &cmp) -> double & { return cmp.weight; };
0049
0050 normalizeWeights(cmps, proj);
0051
0052 auto newEnd = std::remove_if(cmps.begin(), cmps.end(), [&](auto &cmp) {
0053 return proj(cmp) < weightCutoff;
0054 });
0055
0056
0057 if (std::distance(cmps.begin(), newEnd) == 0) {
0058 cmps = {*std::max_element(cmps.begin(), cmps.end(), [&](auto &a, auto &b) {
0059 return proj(a) < proj(b);
0060 })};
0061 cmps.front().weight = 1.0;
0062 } else {
0063 cmps.erase(newEnd, cmps.end());
0064 normalizeWeights(cmps, proj);
0065 }
0066 }
0067
0068 double detail::Gsf::applyBetheHeitler(
0069 const GeometryContext &geoContext, const Surface &surface,
0070 Direction direction, const BoundTrackParameters &initialParameters,
0071 double initialWeight, const BetheHeitlerApprox &betheHeitlerApprox,
0072 std::vector<BetheHeitlerApprox::Component> &betheHeitlerCache,
0073 double weightCutoff, std::vector<GsfComponent> &componentCache,
0074 std::size_t &nInvalidBetheHeitler, double &maxPathXOverX0,
0075 const Logger &logger) {
0076 const double initialMomentum = initialParameters.absoluteMomentum();
0077 const ParticleHypothesis &particleHypothesis =
0078 initialParameters.particleHypothesis();
0079
0080
0081 MaterialSlab slab = surface.surfaceMaterial()->materialSlab(
0082 initialParameters.position(geoContext), direction,
0083 MaterialUpdateMode::FullUpdate);
0084
0085 const double pathCorrection =
0086 surface.pathCorrection(geoContext, initialParameters.position(geoContext),
0087 initialParameters.direction());
0088 slab.scaleThickness(pathCorrection);
0089
0090 const double pathXOverX0 = slab.thicknessInX0();
0091 maxPathXOverX0 = std::max(maxPathXOverX0, pathXOverX0);
0092
0093
0094 if (!betheHeitlerApprox.validXOverX0(pathXOverX0)) {
0095 ++nInvalidBetheHeitler;
0096 ACTS_DEBUG("Bethe-Heitler approximation encountered invalid value for x/x0="
0097 << pathXOverX0 << " at surface " << surface.geometryId());
0098 }
0099
0100
0101 betheHeitlerCache.resize(betheHeitlerApprox.maxComponents());
0102 const auto mixture =
0103 betheHeitlerApprox.mixture(pathXOverX0, betheHeitlerCache);
0104
0105
0106 for (const GaussianComponent &gaussian : mixture) {
0107
0108
0109 const double newWeight = gaussian.weight * initialWeight;
0110
0111 if (newWeight < weightCutoff) {
0112 ACTS_VERBOSE("Skip component with weight " << newWeight);
0113 continue;
0114 }
0115
0116 if (gaussian.mean < 1.e-8) {
0117 ACTS_WARNING("Skip component with gaussian " << gaussian.mean << " +- "
0118 << gaussian.var);
0119 continue;
0120 }
0121
0122
0123 BoundVector newPars = initialParameters.parameters();
0124
0125 const auto delta_p = [&]() {
0126 if (direction == Direction::Forward()) {
0127 return initialMomentum * (gaussian.mean - 1.);
0128 } else {
0129 return initialMomentum * (1. / gaussian.mean - 1.);
0130 }
0131 }();
0132
0133 assert(initialMomentum + delta_p > 0. && "new momentum must be > 0");
0134 newPars[eBoundQOverP] = particleHypothesis.qOverP(
0135 initialMomentum + delta_p, initialParameters.charge());
0136
0137
0138 BoundMatrix newCov = initialParameters.covariance().value();
0139
0140 const auto varInvP = [&]() {
0141 if (direction == Direction::Forward()) {
0142 const double f = 1. / (initialMomentum * gaussian.mean);
0143 return f * f * gaussian.var;
0144 } else {
0145 return gaussian.var / (initialMomentum * initialMomentum);
0146 }
0147 }();
0148
0149 newCov(eBoundQOverP, eBoundQOverP) += varInvP;
0150 assert(std::isfinite(newCov(eBoundQOverP, eBoundQOverP)) &&
0151 "new cov not finite");
0152
0153
0154 componentCache.push_back({newWeight, newPars, newCov});
0155 }
0156
0157 return pathXOverX0;
0158 }
0159
0160 }