Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:46:09

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/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   // In case we would remove all components, keep only the largest
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   // Evaluate material slab
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   // 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 < 1.e-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 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     // compute inverse variance of p from mixture and update covariance
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     // Set the remaining things and push to vector
0154     componentCache.push_back({newWeight, newPars, newCov});
0155   }
0156 
0157   return pathXOverX0;
0158 }
0159 
0160 }  // namespace Acts