Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-20 08:41:53

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 <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/EventData/MultiTrajectory.hpp"
0014 #include "Acts/EventData/TrackStatePropMask.hpp"
0015 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0016 #include "Acts/Geometry/GeometryIdentifier.hpp"
0017 #include "Acts/Surfaces/PlaneSurface.hpp"
0018 #include "Acts/Surfaces/RectangleBounds.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 #include "Acts/TrackFinding/MeasurementSelector.hpp"
0021 #include "Acts/Utilities/Logger.hpp"
0022 
0023 #include <array>
0024 #include <cmath>
0025 #include <cstdint>
0026 #include <limits>
0027 #include <memory>
0028 #include <numbers>
0029 #include <vector>
0030 
0031 namespace Acts::Test {
0032 
0033 BOOST_AUTO_TEST_SUITE(MeasurementSelectorTests)
0034 
0035 namespace {
0036 
0037 std::shared_ptr<Surface> makeSurface() {
0038   auto bounds = std::make_shared<RectangleBounds>(100., 100.);
0039   auto surface =
0040       Surface::makeShared<PlaneSurface>(Transform3::Identity(), bounds);
0041   surface->assignGeometryId(
0042       GeometryIdentifier().withVolume(1).withLayer(1).withSensitive(1));
0043   return surface;
0044 }
0045 
0046 /// Adds a track state candidate on @p surface.
0047 ///
0048 /// A fit that diverges ends up with non-finite predicted parameters, and
0049 /// inverting a sufficiently inflated predicted covariance can overflow and
0050 /// yield a non-finite chi2 as well. The non-finite value is injected directly
0051 /// rather than provoked through an overflow, so that the chi2 is non-finite on
0052 /// every platform instead of depending on how the matrix inverse rounds.
0053 VectorMultiTrajectory::TrackStateProxy addCandidate(
0054     VectorMultiTrajectory& traj, const std::shared_ptr<Surface>& surface,
0055     bool diverged) {
0056   auto ts = traj.makeTrackState(TrackStatePropMask::All);
0057   ts.setReferenceSurface(surface);
0058 
0059   ts.predicted() = BoundVector::Zero();
0060   // Avoid theta = 0, whose pseudorapidity is infinite, since the selector bins
0061   // its cuts in eta.
0062   ts.predicted()[eBoundTheta] = std::numbers::pi / 2.;
0063   if (diverged) {
0064     ts.predicted()[eBoundLoc0] = std::numeric_limits<double>::quiet_NaN();
0065   }
0066   ts.predictedCovariance() = BoundMatrix::Identity() * 1e-2;
0067 
0068   ts.allocateCalibrated(2);
0069   ts.calibrated<2>() << 0.0, 0.0;
0070   ts.calibratedCovariance<2>() = SquareMatrix<2>::Identity() * 1e-2;
0071   ts.setProjectorSubspaceIndices(
0072       std::array<std::uint8_t, 2>{eBoundLoc0, eBoundLoc1});
0073   return ts;
0074 }
0075 
0076 }  // namespace
0077 
0078 /// Every comparison against NaN is false, so a candidate with a non-finite
0079 /// chi2 used to leave minIndex unset while still being counted as passing the
0080 /// chi2 cut. The selector then returned `candidates.begin() - 1`, which the
0081 /// caller dereferences.
0082 BOOST_AUTO_TEST_CASE(NonFiniteChi2IsRejected) {
0083   auto logger = getDefaultLogger("MeasurementSelector", Logging::INFO);
0084   auto surface = makeSurface();
0085 
0086   VectorMultiTrajectory traj;
0087   std::vector<VectorMultiTrajectory::TrackStateProxy> candidates{
0088       addCandidate(traj, surface, true)};
0089 
0090   MeasurementSelectorCuts cuts;
0091   cuts.chi2CutOff = {15};
0092   cuts.numMeasurementsCutOff = {1};
0093   MeasurementSelector selector{cuts};
0094 
0095   bool isOutlier = false;
0096   auto result =
0097       selector.select<VectorMultiTrajectory>(candidates, isOutlier, *logger);
0098 
0099   BOOST_REQUIRE(result.ok());
0100   BOOST_REQUIRE(!std::isfinite(candidates.front().chi2()));
0101 
0102   auto [begin, end] = *result;
0103   // The returned range must be a valid subrange of the candidates.
0104   BOOST_CHECK_GE(begin - candidates.begin(), 0);
0105   BOOST_CHECK_LE(end - candidates.begin(),
0106                  static_cast<std::ptrdiff_t>(candidates.size()));
0107   // The only candidate is unusable, so nothing may be selected.
0108   BOOST_CHECK_EQUAL(end - begin, 0);
0109 }
0110 
0111 /// A candidate with a finite chi2 must still be selected when a non-finite one
0112 /// is present alongside it, rather than the non-finite one being preferred.
0113 BOOST_AUTO_TEST_CASE(FiniteChi2StillSelectedAlongsideNonFinite) {
0114   auto logger = getDefaultLogger("MeasurementSelector", Logging::INFO);
0115   auto surface = makeSurface();
0116 
0117   VectorMultiTrajectory traj;
0118   std::vector<VectorMultiTrajectory::TrackStateProxy> candidates{
0119       addCandidate(traj, surface, true), addCandidate(traj, surface, false)};
0120 
0121   MeasurementSelectorCuts cuts;
0122   cuts.chi2CutOff = {15};
0123   cuts.numMeasurementsCutOff = {1};
0124   MeasurementSelector selector{cuts};
0125 
0126   bool isOutlier = false;
0127   auto result =
0128       selector.select<VectorMultiTrajectory>(candidates, isOutlier, *logger);
0129 
0130   BOOST_REQUIRE(result.ok());
0131   auto [begin, end] = *result;
0132   BOOST_CHECK_GE(begin - candidates.begin(), 0);
0133   BOOST_REQUIRE_EQUAL(end - begin, 1);
0134   BOOST_CHECK(std::isfinite(begin->chi2()));
0135 }
0136 
0137 BOOST_AUTO_TEST_SUITE_END()
0138 
0139 }  // namespace Acts::Test