Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-06 08:10:00

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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/MaterialSlab.hpp"
0016 
0017 #include <cstddef>
0018 #include <cstdint>
0019 #include <span>
0020 
0021 namespace Acts {
0022 
0023 double detail::Gsf::calculateDeterminant(
0024     const double *fullCalibratedCovariance,
0025     TrackStateTraits<kMeasurementSizeMax, true>::Covariance predictedCovariance,
0026     BoundSubspaceIndices projector, unsigned int calibratedSize) {
0027   return visit_measurement(calibratedSize, [&](auto N) {
0028     constexpr std::size_t kMeasurementSize = decltype(N)::value;
0029     std::span<const std::uint8_t, kMeasurementSize> validSubspaceIndices(
0030         projector.begin(), projector.begin() + kMeasurementSize);
0031     FixedBoundSubspaceHelper<kMeasurementSize> subspaceHelper(
0032         validSubspaceIndices);
0033 
0034     typename Acts::TrackStateTraits<
0035         kMeasurementSize, true>::CalibratedCovariance calibratedCovariance{
0036         fullCalibratedCovariance};
0037 
0038     const auto H = subspaceHelper.projector();
0039 
0040     return (H * predictedCovariance * H.transpose() + calibratedCovariance)
0041         .determinant();
0042   });
0043 }
0044 
0045 void detail::Gsf::removeLowWeightComponents(std::vector<GsfComponent> &cmps,
0046                                             double weightCutoff) {
0047   auto proj = [](auto &cmp) -> double & { return cmp.weight; };
0048 
0049   normalizeWeights(cmps, proj);
0050 
0051   auto newEnd = std::remove_if(cmps.begin(), cmps.end(), [&](auto &cmp) {
0052     return proj(cmp) < weightCutoff;
0053   });
0054 
0055   // In case we would remove all components, keep only the largest
0056   if (std::distance(cmps.begin(), newEnd) == 0) {
0057     cmps = {*std::max_element(cmps.begin(), cmps.end(), [&](auto &a, auto &b) {
0058       return proj(a) < proj(b);
0059     })};
0060     cmps.front().weight = 1.0;
0061   } else {
0062     cmps.erase(newEnd, cmps.end());
0063     normalizeWeights(cmps, proj);
0064   }
0065 }
0066 
0067 double detail::Gsf::applyBetheHeitler(
0068     const GeometryContext &geoContext, const Surface &surface,
0069     Direction direction, const BoundTrackParameters &initialParameters,
0070     double initialWeight, const BetheHeitlerApprox &betheHeitlerApprox,
0071     std::vector<BetheHeitlerApprox::Component> &betheHeitlerCache,
0072     double weightCutoff, std::vector<GsfComponent> &componentCache,
0073     std::size_t &nInvalidBetheHeitler, double &maxPathXOverX0,
0074     const Logger &logger) {
0075   const double initialMomentum = initialParameters.absoluteMomentum();
0076   const ParticleHypothesis &particleHypothesis =
0077       initialParameters.particleHypothesis();
0078 
0079   // Evaluate material slab
0080   const Vector2 lposition =
0081       initialParameters.parameters().template segment<2>(eBoundLoc0);
0082   MaterialSlab slab = surface.materialSlab(lposition, 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   // Emit a warning if the approximation is not valid for this x/x0
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   // Get the mixture
0101   betheHeitlerCache.resize(betheHeitlerApprox.maxComponents());
0102   const auto mixture =
0103       betheHeitlerApprox.mixture(pathXOverX0, betheHeitlerCache);
0104 
0105   // Create all possible new components
0106   for (const GaussianComponent &gaussian : mixture) {
0107     // Here we combine the new child weight with the parent weight.
0108     // However, this must be later re-adjusted
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 < 1e-8) {
0117       ACTS_WARNING("Skip component with gaussian " << gaussian.mean << " +- "
0118                                                    << gaussian.var);
0119       continue;
0120     }
0121 
0122     // compute delta p from mixture and update parameters
0123     BoundVector newPars = initialParameters.parameters();
0124 
0125     const double deltaP = [&]() {
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 + deltaP > 0 && "new momentum must be > 0");
0134     newPars[eBoundQOverP] = particleHypothesis.qOverP(
0135         initialMomentum + deltaP, initialParameters.charge());
0136 
0137     // compute inverse variance of p from mixture and update covariance
0138     BoundMatrix newCov = initialParameters.covariance().value();
0139 
0140     const double 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     // Set the remaining things and push to vector
0154     componentCache.emplace_back(newWeight, newPars, newCov);
0155   }
0156 
0157   return pathXOverX0;
0158 }
0159 
0160 }  // namespace Acts