Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 08:21:44

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 // Exercises `measurementResidual`, which compares track state parameters
0010 // against the state's own calibrated measurement.
0011 
0012 #include <boost/test/unit_test.hpp>
0013 
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/EventData/TrackContainer.hpp"
0016 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0017 #include "Acts/EventData/VectorTrackContainer.hpp"
0018 #include "Acts/Surfaces/PlaneSurface.hpp"
0019 #include "Acts/Surfaces/RectangleBounds.hpp"
0020 #include "ActsExamples/EventData/Track.hpp"
0021 #include "ActsExamples/Validation/ParametersOnSurface.hpp"
0022 
0023 #include <array>
0024 #include <cstdint>
0025 #include <memory>
0026 #include <span>
0027 #include <utility>
0028 
0029 using namespace Acts;
0030 using namespace ActsExamples;
0031 
0032 namespace {
0033 
0034 /// Local coordinates of the measurement, chosen so that both components of a
0035 /// 2D measurement differ from the parameters below.
0036 constexpr double measLoc0 = 1.5;
0037 constexpr double measLoc1 = -2.5;
0038 /// Variances of the measurement.
0039 constexpr double measVar0 = 0.04;
0040 constexpr double measVar1 = 0.09;
0041 /// Local coordinates of the reconstructed parameters.
0042 constexpr double recoLoc0 = 1.7;
0043 constexpr double recoLoc1 = -2.1;
0044 /// Variances of the reconstructed parameters.
0045 constexpr double recoVar0 = 0.01;
0046 constexpr double recoVar1 = 0.02;
0047 
0048 std::shared_ptr<PlaneSurface> makeSurface() {
0049   return Surface::makeShared<PlaneSurface>(
0050       Transform3::Identity(), std::make_shared<RectangleBounds>(100., 100.));
0051 }
0052 
0053 /// Reconstructed parameters with a diagonal covariance on @p surface.
0054 BoundTrackParameters makeParameters(
0055     const std::shared_ptr<const Surface>& surface) {
0056   BoundVector parameters = BoundVector::Zero();
0057   parameters[eBoundLoc0] = recoLoc0;
0058   parameters[eBoundLoc1] = recoLoc1;
0059 
0060   BoundMatrix covariance = BoundMatrix::Zero();
0061   covariance(eBoundLoc0, eBoundLoc0) = recoVar0;
0062   covariance(eBoundLoc1, eBoundLoc1) = recoVar1;
0063 
0064   return BoundTrackParameters(surface, parameters, covariance,
0065                               ParticleHypothesis::pion());
0066 }
0067 
0068 /// Holds the container backing the single track state under test, so the
0069 /// returned proxy stays valid for the lifetime of the fixture.
0070 struct Fixture {
0071   VectorTrackContainer trackBackend;
0072   VectorMultiTrajectory trajectory;
0073   Acts::TrackContainer<VectorTrackContainer, VectorMultiTrajectory,
0074                        Acts::detail::RefHolder>
0075       container{trackBackend, trajectory};
0076 
0077   std::shared_ptr<PlaneSurface> surface = makeSurface();
0078 
0079   /// Make the single track state.
0080   ///
0081   /// @param indices the bound indices the measurement constrains; an empty
0082   ///        range leaves the state without a measurement
0083   /// @return the state as a const proxy
0084   ConstTrackStateProxy makeState(std::span<const std::uint8_t> indices) {
0085     // a second state would invalidate the proxy returned for the first
0086     BOOST_REQUIRE(constContainer == nullptr);
0087 
0088     auto state = container.trackStateContainer().makeTrackState();
0089     state.setReferenceSurface(surface);
0090 
0091     if (!indices.empty()) {
0092       state.setProjectorSubspaceIndices(indices);
0093 
0094       state.allocateCalibrated(indices.size());
0095       auto calibrated = state.effectiveCalibrated();
0096       auto calibratedCovariance = state.effectiveCalibratedCovariance();
0097       calibratedCovariance.setZero();
0098 
0099       const std::array<double, 2> values{measLoc0, measLoc1};
0100       const std::array<double, 2> variances{measVar0, measVar1};
0101       for (std::size_t i = 0; i < indices.size(); ++i) {
0102         calibrated[i] = values.at(i);
0103         calibratedCovariance(i, i) = variances.at(i);
0104       }
0105     }
0106 
0107     constContainer = std::make_unique<ConstTrackContainer>(
0108         std::make_shared<ConstVectorTrackContainer>(trackBackend),
0109         std::make_shared<ConstVectorMultiTrajectory>(trajectory));
0110     return constContainer->trackStateContainer().getTrackState(state.index());
0111   }
0112 
0113   std::unique_ptr<ConstTrackContainer> constContainer;
0114 };
0115 
0116 }  // namespace
0117 
0118 BOOST_AUTO_TEST_SUITE(ValidationMeasurementResidual)
0119 
0120 BOOST_AUTO_TEST_CASE(TwoDimensionalMeasurement) {
0121   Fixture fixture;
0122   const std::array<std::uint8_t, 2> indices{eBoundLoc0, eBoundLoc1};
0123   const ConstTrackStateProxy state = fixture.makeState(indices);
0124 
0125   const auto residual = measurementResidual(
0126       state, makeParameters(fixture.surface), TrackParameterType::Predicted);
0127   BOOST_REQUIRE(residual.has_value());
0128 
0129   BOOST_CHECK_EQUAL(residual->subspace.size(), 2u);
0130   BOOST_CHECK(residual->subspace.contains(eBoundLoc0));
0131   BOOST_CHECK(residual->subspace.contains(eBoundLoc1));
0132 
0133   // the reference is subtracted from the reconstructed value
0134   BOOST_CHECK_CLOSE(residual->residual[eBoundLoc0], recoLoc0 - measLoc0, 1e-9);
0135   BOOST_CHECK_CLOSE(residual->residual[eBoundLoc1], recoLoc1 - measLoc1, 1e-9);
0136 
0137   // predicted parameters do not use the measurement, so the covariances add
0138   BOOST_CHECK_CLOSE(residual->covariance(eBoundLoc0, eBoundLoc0),
0139                     measVar0 + recoVar0, 1e-9);
0140   BOOST_CHECK_CLOSE(residual->covariance(eBoundLoc1, eBoundLoc1),
0141                     measVar1 + recoVar1, 1e-9);
0142 
0143   // everything outside the measured subspace stays zero
0144   BOOST_CHECK_EQUAL(residual->residual[eBoundQOverP], 0.);
0145   BOOST_CHECK_EQUAL(residual->covariance(eBoundTheta, eBoundTheta), 0.);
0146 }
0147 
0148 BOOST_AUTO_TEST_CASE(CovarianceSignFollowsTheParameterType) {
0149   using enum TrackParameterType;
0150 
0151   Fixture fixture;
0152   const std::array<std::uint8_t, 2> indices{eBoundLoc0, eBoundLoc1};
0153   const ConstTrackStateProxy state = fixture.makeState(indices);
0154 
0155   // only the parameters that consumed the state's own measurement are
0156   // correlated with it, so only their covariance subtracts
0157   constexpr std::array<std::pair<TrackParameterType, bool>, 4> cases{
0158       {{Predicted, false},
0159        {Filtered, true},
0160        {Smoothed, true},
0161        {Unbiased, false}}};
0162 
0163   for (const auto& [parameterType, correlated] : cases) {
0164     const auto residual = measurementResidual(
0165         state, makeParameters(fixture.surface), parameterType);
0166     BOOST_REQUIRE(residual.has_value());
0167 
0168     const double sign = correlated ? -1. : 1.;
0169     BOOST_CHECK_CLOSE(residual->covariance(eBoundLoc0, eBoundLoc0),
0170                       measVar0 + sign * recoVar0, 1e-9);
0171     BOOST_CHECK_CLOSE(residual->covariance(eBoundLoc1, eBoundLoc1),
0172                       measVar1 + sign * recoVar1, 1e-9);
0173 
0174     // the residual itself does not depend on the parameter type
0175     BOOST_CHECK_CLOSE(residual->residual[eBoundLoc0], recoLoc0 - measLoc0,
0176                       1e-9);
0177   }
0178 }
0179 
0180 BOOST_AUTO_TEST_CASE(OneDimensionalMeasurement) {
0181   Fixture fixture;
0182   const std::array<std::uint8_t, 1> indices{eBoundLoc0};
0183   const ConstTrackStateProxy state = fixture.makeState(indices);
0184 
0185   const auto residual = measurementResidual(
0186       state, makeParameters(fixture.surface), TrackParameterType::Predicted);
0187   BOOST_REQUIRE(residual.has_value());
0188 
0189   // a strip constrains loc0 only, so loc1 is not part of the subspace and
0190   // must not be filled by the caller
0191   BOOST_CHECK_EQUAL(residual->subspace.size(), 1u);
0192   BOOST_CHECK(residual->subspace.contains(eBoundLoc0));
0193   BOOST_CHECK(!residual->subspace.contains(eBoundLoc1));
0194 
0195   BOOST_CHECK_CLOSE(residual->residual[eBoundLoc0], recoLoc0 - measLoc0, 1e-9);
0196   BOOST_CHECK_CLOSE(residual->covariance(eBoundLoc0, eBoundLoc0),
0197                     measVar0 + recoVar0, 1e-9);
0198 
0199   BOOST_CHECK_EQUAL(residual->residual[eBoundLoc1], 0.);
0200   BOOST_CHECK_EQUAL(residual->covariance(eBoundLoc1, eBoundLoc1), 0.);
0201 }
0202 
0203 BOOST_AUTO_TEST_CASE(NoMeasurement) {
0204   Fixture fixture;
0205   const ConstTrackStateProxy state = fixture.makeState({});
0206 
0207   BOOST_CHECK(!measurementResidual(state, makeParameters(fixture.surface),
0208                                    TrackParameterType::Predicted)
0209                    .has_value());
0210 }
0211 
0212 BOOST_AUTO_TEST_SUITE_END()