ATLAS Offline Software
Loading...
Searching...
No Matches
TrackParamsEstimationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp"
9#include "Acts/SpacePointFormation2/StripSpacePointCalibration.hpp"
10#include "Acts/EventData/StripSpacePointCalibrationDetails.hpp"
11#include "Acts/EventData/TransformationHelpers.hpp"
12
13#include <algorithm>
14#include <ranges>
15
16namespace ActsTrk {
17
18namespace {
19
20template <typename sp_range_t>
21Acts::FreeVector estimateTrackParamsFromSeed(
22 const sp_range_t& spRange,
23 const Acts::Vector3& bField,
24 const std::size_t stripCalibrationIterations) {
25 std::array<const xAOD::SpacePoint*, 3> spArray{};
26 std::array<Acts::Vector3, 3> spPositions{};
27
28 std::size_t i = 0;
29 for (const auto* sp : spRange) {
30 if (sp == nullptr) {
31 throw std::invalid_argument("Empty space point found.");
32 }
33 if (i >= spArray.size()) {
34 throw std::invalid_argument("More than 3 space points provided.");
35 }
36 spArray[i] = sp;
37 spPositions[i] = Acts::Vector3(sp->x(), sp->y(), sp->z());
38 ++i;
39 }
40 if (i < spArray.size()) {
41 throw std::invalid_argument("Less than 3 space points provided.");
42 }
43
44 const bool hasStrip = std::ranges::any_of(spArray, [](const xAOD::SpacePoint* sp) {
45 return sp->elementIdList().size() > 1;
46 });
47 if (hasStrip) {
48 std::array<Acts::Vector3, 3> spTangents{};
49
50 for (std::size_t i = 0; i < stripCalibrationIterations; ++i) {
51 Acts::estimateTrackParamsFromSeed(
52 spPositions[0], 0, spPositions[1], spPositions[2], bField,
53 &spTangents[0], &spTangents[1], &spTangents[2]);
54
55 for (std::size_t j = 0; j < spArray.size(); ++j) {
56 const xAOD::SpacePoint* sp = spArray[j];
57 const bool isStrip = sp->elementIdList().size() > 1;
58 if (!isStrip) {
59 continue;
60 }
61
62 Acts::OuterStripSpacePointCalibrationDetails calibrationDetails;
63 Eigen::Map<Eigen::Vector3f>(calibrationDetails.outerCenter.data()) = sp->topStripCenter();
64 Eigen::Map<Eigen::Vector3f>(calibrationDetails.innerToOuterSeparation.data()) = sp->stripCenterDistance();
65 Eigen::Map<Eigen::Vector3f>(calibrationDetails.outerHalfVector.data()) = sp->topHalfStripLength() * sp->topStripDirection();
66 Eigen::Map<Eigen::Vector3f>(calibrationDetails.innerHalfVector.data()) = sp->bottomHalfStripLength() * sp->bottomStripDirection();
67 const Acts::OuterStripSpacePointCalibrationDetailsDerived derivedCalibrationDetails =
68 Acts::deriveOuterStripSpacePointCalibrationDetails(calibrationDetails);
69
70 const std::optional<Eigen::Vector3f> calibratedPosition =
71 Acts::calibrateOuterStripSpacePoint(spTangents[j].cast<float>(), derivedCalibrationDetails);
72 if (!calibratedPosition.has_value()) {
73 continue;
74 }
75 spPositions[j] = calibratedPosition->cast<double>();
76 }
77 }
78 }
79
80 return Acts::estimateTrackParamsFromSeed(
81 spPositions[0], 0, spPositions[1], spPositions[2], bField);
82}
83
84}
85
87 const std::string& name,
88 const IInterface* parent)
89 : base_class(type, name, parent)
90 {}
91
93 {
94 ATH_MSG_INFO( "Initializing " << name() << "..." );
95
96 ATH_MSG_DEBUG( "Properties Summary:" );
97 ATH_MSG_DEBUG( " " << m_sigmaLoc0 );
98 ATH_MSG_DEBUG( " " << m_sigmaLoc1 );
99 ATH_MSG_DEBUG( " " << m_sigmaPhi );
100 ATH_MSG_DEBUG( " " << m_sigmaTheta );
102 ATH_MSG_DEBUG( " " << m_sigmaT0 );
104 ATH_MSG_DEBUG( " " << m_bFieldMode );
105 ATH_MSG_DEBUG( " " << m_firstSp );
107
108 m_logger = makeActsAthenaLogger(this, "Acts");
109
110 m_extrapolator = Extrapolator(Stepper(std::make_shared<ATLASMagneticFieldWrapper>()), Navigator(), logger().cloneWithSuffix("Prop"));
111
113
114 return StatusCode::SUCCESS;
115 }
116
117 std::optional<Acts::BoundTrackParameters>
119 const ActsTrk::Seed& seed,
120 bool useTopSp,
121 const Acts::GeometryContext& geoContext,
122 const Acts::MagneticFieldContext& magFieldContext,
123 std::function<const Acts::Surface&(const ActsTrk::Seed& seed, bool useTopSp)> retrieveSurface) const
124 {
125 const auto& sp_collection = seed.sp();
126 if ( sp_collection.size() < 3 ) return std::nullopt;
127 const xAOD::SpacePoint* bottom_sp = (useTopSp && m_bFieldMode != 2) ? sp_collection.back() : sp_collection.front();
128
129 // Magnetic Field
130 ATLASMagneticFieldWrapper magneticField;
131 Acts::MagneticFieldProvider::Cache magFieldCache = magneticField.makeCache( magFieldContext );
132 Acts::Vector3 bField = *magneticField.getField( Acts::Vector3(bottom_sp->x(), bottom_sp->y(), bottom_sp->z()),
133 magFieldCache );
134 if (m_bFieldMode == 1) {
135 bField[0] = 0.0;
136 bField[1] = 0.0;
137 }
138
139 // Get the surface
140 const Acts::Surface& surface = retrieveSurface(seed, useTopSp);
141
143 seed,
144 useTopSp,
145 geoContext,
146 magFieldContext,
147 surface,
148 bField);
149 }
150
151 std::optional<Acts::BoundTrackParameters>
153 const ActsTrk::Seed& seed,
154 bool useTopSp,
155 const Acts::GeometryContext& geoContext,
156 const Acts::MagneticFieldContext& magFieldContext,
157 const Acts::Surface& surface,
158 const Acts::Vector3& bField) const
159 {
160 // Get SPs
161 const auto& sp_collection = seed.sp();
162 const std::size_t nSp = sp_collection.size();
163 if (nSp < 3) return std::nullopt;
164
165 // Function to extract the values from sp_collection
166 const auto sp_collection_extract = std::views::transform([&sp_collection, useTopSp](std::size_t i) {
167 return sp_collection.at(useTopSp ? sp_collection.size() - i - 1 : i);
168 });
169
170 // Compute free parameters
171 Acts::FreeVector freeParams = estimateTrackParamsFromSeed(m_spacePointIndicesFun(nSp) | sp_collection_extract, bField, m_stripCalibrationIterations);
172
173 if (m_useLongSeeds == 1 && nSp > 3ul) {
174 const auto spacePointIndicesFun2 = [](std::size_t nSp) -> std::array<std::size_t, 3> {
175 return {0, nSp / 2ul, nSp - 1};
176 };
177 const Acts::FreeVector freeParams2 = estimateTrackParamsFromSeed(spacePointIndicesFun2(nSp) | sp_collection_extract, bField, m_stripCalibrationIterations);
178 ATH_MSG_DEBUG("update seed p = " << 1.0 / freeParams[Acts::eFreeQOverP] << " to " << 1.0 / freeParams2[Acts::eFreeQOverP]);
179 freeParams[Acts::eFreeQOverP] = freeParams2[Acts::eFreeQOverP];
180 }
181
182 if (useTopSp) {
183 // reverse direction so momentum vector pointing outwards
184 freeParams = Acts::reflectFreeParameters(freeParams);
185 }
186
187 // Convert free params to curvilinear params for extrapolation
188 Acts::BoundTrackParameters curvilinearParams = Acts::BoundTrackParameters::createCurvilinear(
189 freeParams.segment<4>(Acts::eFreePos0),
190 freeParams.segment<3>(Acts::eFreeDir0),
191 freeParams[Acts::eFreeQOverP],
192 std::nullopt,
193 Acts::ParticleHypothesis::pion());
194
195 // Extrapolate to surface
196 Acts::PropagatorPlainOptions propOptions(geoContext, magFieldContext);
197 propOptions.direction = Acts::Direction::fromScalarZeroAsPositive(
198 surface.intersect(
199 geoContext,
200 freeParams.segment<3>(Acts::eFreePos0),
201 freeParams.segment<3>(Acts::eFreeDir0)
202 ).closest().pathLength());
203
204 std::optional<Acts::BoundTrackParameters> boundParams;
205 auto boundParamsResult =
206 m_extrapolator->propagateToSurface(curvilinearParams, surface, propOptions);
207
208 if (!boundParamsResult.ok()) {
209 ATH_MSG_DEBUG("Extrapolation failed");
211 // Fallback: use curvilinear parameters instead of failing
212 ATH_MSG_DEBUG("Using curvilinear parameters due to propagation failure");
213 boundParams = curvilinearParams;
214 } else {
215 return std::nullopt;
216 }
217 } else {
218 boundParams = *boundParamsResult;
219 }
220
221
222 // Estimate covariance
223 Acts::EstimateTrackParamCovarianceConfig covarianceEstimationConfig = {
225 .initialSigmaPtRel = m_initialSigmaPtRel,
226 .initialVarInflation = Eigen::Map<const Acts::BoundVector>(m_initialVarInflation.value().data()),
227 .noTimeVarInflation = 1.0,
228 };
229 boundParams->covariance() = Acts::estimateTrackParamCovariance(
230 covarianceEstimationConfig,
231 boundParams->parameters(),
232 false);
233
234 return boundParams;
235 }
236
237 // Function to return which 3 SPs of a seed to use
239 if (m_useLongSeeds == 2) {
240 return [](std::size_t nSp) -> std::array<std::size_t, 3> {
241 if (nSp > 3ul)
242 return {0, nSp / 2ul, nSp - 1};
243 else
244 return {0, 1, 2};
245 };
246 } else if (m_firstSp > 0ul) {
247 std::size_t firstSp = m_firstSp;
248 return [firstSp](std::size_t nSp) -> std::array<std::size_t, 3> {
249 if (nSp > 3ul) {
250 std::size_t first = std::min(firstSp, nSp - 3ul);
251 return {first, first + 1, first + 2};
252 } else
253 return {0, 1, 2};
254 };
255 } else {
256 return [](std::size_t) -> std::array<std::size_t, 3> {
257 return {0, 1, 2};
258 };
259 }
260 };
261
262}
263// namespace ActsTrk
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
static Double_t sp
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Acts::Result< Acts::Vector3 > getField(const Acts::Vector3 &position, Acts::MagneticFieldProvider::Cache &gcache) const override
MagneticFieldProvider::Cache makeCache(const Acts::MagneticFieldContext &mctx) const override
std::function< std::array< std::size_t, 3 >(std::size_t)> SpacePointIndicesFun_t
const Acts::Logger & logger() const
Private access to the logger.
std::unique_ptr< const Acts::Logger > m_logger
logging instance
SpacePointIndicesFun_t spacePointIndicesFun() const override
TrackParamsEstimationTool(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< std::vector< double > > m_initialVarInflation
Gaudi::Property< std::size_t > m_firstSp
std::optional< Extrapolator > m_extrapolator
Gaudi::Property< std::size_t > m_stripCalibrationIterations
virtual std::optional< Acts::BoundTrackParameters > estimateTrackParameters(const ActsTrk::Seed &seed, bool useTopSp, const Acts::GeometryContext &geoContext, const Acts::MagneticFieldContext &magFieldContext, std::function< const Acts::Surface &(const ActsTrk::Seed &seed, bool useTopSp)> retrieveSurface) const override
float z() const
float y() const
float x() const
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)