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/SpacePointFormation/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 ATH_MSG_DEBUG( " " << m_refitSeeds );
108
109 ATH_CHECK(m_fitterTool.retrieve(EnableTool{m_refitSeeds}));
110
111 m_logger = makeActsAthenaLogger(this, "Acts");
112
113 m_extrapolator = Extrapolator(Stepper(std::make_shared<ATLASMagneticFieldWrapper>()), Navigator(), logger().cloneWithSuffix("Prop"));
114
116
117 if (m_refitSeeds) {
120 }
121
122 return StatusCode::SUCCESS;
123 }
124
125 std::pair<std::optional<Acts::BoundTrackParameters>, TrackParamsEstimationTool::EstimationStatus>
127 const ActsTrk::Seed& seed,
128 bool reverseSearch,
129 const Acts::GeometryContext& geoContext,
130 const Acts::MagneticFieldContext& magFieldContext,
131 const Acts::CalibrationContext& calContext,
132 std::function<const Acts::Surface&(const ActsTrk::Seed& seed, bool useTopSp)> retrieveSurface) const
133 {
134 bool useTopSp = estimateFromTopSp(reverseSearch);
135
136 const auto& sp_collection = seed.sp();
137 if ( sp_collection.size() < 3 ) return {std::nullopt, kNoSeedRefit};
138 const xAOD::SpacePoint* bottom_sp = (useTopSp && m_bFieldMode != 2) ? sp_collection.back() : sp_collection.front();
139
140 // Magnetic Field
141 ATLASMagneticFieldWrapper magneticField;
142 Acts::MagneticFieldProvider::Cache magFieldCache = magneticField.makeCache( magFieldContext );
143 Acts::Vector3 bField = *magneticField.getField( Acts::Vector3(bottom_sp->x(), bottom_sp->y(), bottom_sp->z()),
144 magFieldCache );
145 if (m_bFieldMode == 1) {
146 bField[0] = 0.0;
147 bField[1] = 0.0;
148 }
149
150 // Get the surface
151 const Acts::Surface& surface = retrieveSurface(seed, useTopSp);
152
154 seed,
155 reverseSearch,
156 geoContext,
157 magFieldContext,
158 calContext,
159 surface,
160 bField);
161 }
162
163 std::pair<std::optional<Acts::BoundTrackParameters>, TrackParamsEstimationTool::EstimationStatus>
165 const ActsTrk::Seed& seed,
166 bool reverseSearch,
167 const Acts::GeometryContext& geoContext,
168 const Acts::MagneticFieldContext& magFieldContext,
169 const Acts::CalibrationContext& calContext,
170 const Acts::Surface& surface,
171 const Acts::Vector3& bField) const
172 {
173 bool useTopSp = estimateFromTopSp(reverseSearch);
174
175 // Get SPs
176 const auto& sp_collection = seed.sp();
177 const std::size_t nSp = sp_collection.size();
178 if (nSp < 3) return {std::nullopt, kNoSeedRefit};
179
180 // Function to extract the values from sp_collection
181 const auto sp_collection_extract = std::views::transform([&sp_collection, useTopSp](std::size_t i) {
182 return sp_collection.at(useTopSp ? sp_collection.size() - i - 1 : i);
183 });
184
185 // Compute free parameters
186 Acts::FreeVector freeParams = estimateTrackParamsFromSeed(m_spacePointIndicesFun(nSp) | sp_collection_extract, bField, m_stripCalibrationIterations);
187
188 if (m_useLongSeeds == 1 && nSp > 3ul) {
189 const auto spacePointIndicesFun2 = [](std::size_t nSp) -> std::array<std::size_t, 3> {
190 return {0, nSp / 2ul, nSp - 1};
191 };
192 const Acts::FreeVector freeParams2 = estimateTrackParamsFromSeed(spacePointIndicesFun2(nSp) | sp_collection_extract, bField, m_stripCalibrationIterations);
193 ATH_MSG_DEBUG("update seed p = " << 1.0 / freeParams[Acts::eFreeQOverP] << " to " << 1.0 / freeParams2[Acts::eFreeQOverP]);
194 freeParams[Acts::eFreeQOverP] = freeParams2[Acts::eFreeQOverP];
195 }
196
197 if (useTopSp) {
198 // reverse direction so momentum vector pointing outwards
199 freeParams = Acts::reflectFreeParameters(freeParams);
200 }
201
202 // Convert free params to curvilinear params for extrapolation
203 Acts::BoundTrackParameters curvilinearParams = Acts::BoundTrackParameters::createCurvilinear(
204 freeParams.segment<4>(Acts::eFreePos0),
205 freeParams.segment<3>(Acts::eFreeDir0),
206 freeParams[Acts::eFreeQOverP],
207 std::nullopt,
208 Acts::ParticleHypothesis::pion());
209
210 // Extrapolate to surface
211 Acts::PropagatorPlainOptions propOptions(geoContext, magFieldContext);
212 propOptions.direction = Acts::Direction::fromScalarZeroAsPositive(
213 surface.intersect(
214 geoContext,
215 freeParams.segment<3>(Acts::eFreePos0),
216 freeParams.segment<3>(Acts::eFreeDir0)
217 ).closest().pathLength());
218
219 std::optional<Acts::BoundTrackParameters> boundParams;
220 auto boundParamsResult =
221 m_extrapolator->propagateToSurface(curvilinearParams, surface, propOptions);
222
223 if (!boundParamsResult.ok()) {
224 ATH_MSG_DEBUG("Extrapolation from " << seed.sp().size() << "-SP seed (" << (useTopSp ? "top" : "bottom") << " start) failed - "
225 << (m_allowPropagatorFailure ? "use curvilinear parameters" : "skip seed"));
227 // Fallback: use curvilinear parameters instead of failing
228 boundParams = curvilinearParams;
229 } else {
230 return {std::nullopt, kNoSeedRefit};
231 }
232 } else {
233 boundParams = *boundParamsResult;
234 }
235
236 // Estimate covariance
237 Acts::EstimateTrackParamCovarianceConfig covarianceEstimationConfig = {
239 .initialSigmaPtRel = m_initialSigmaPtRel,
240 .initialVarInflation = Eigen::Map<const Acts::BoundVector>(m_initialVarInflation.value().data()),
241 .noTimeVarInflation = 1.0,
242 };
243 boundParams->covariance() = Acts::estimateTrackParamCovariance(
244 covarianceEstimationConfig,
245 boundParams->parameters(),
246 false);
247
248 if (!m_refitSeeds) {
249 ATH_MSG_DEBUG("estimateTrackParams from " << seed.sp().size() << "-SP seed (" << (useTopSp ? "top" : "bottom") << " start) succeeded");
250 return {boundParams, kNoSeedRefit};
251 }
252
253 auto refitResult = doRefit(seed, *boundParams, geoContext, magFieldContext, calContext, reverseSearch);
254 ATH_MSG_DEBUG("Refit " << seed.sp().size() << "-SP seed (" << (reverseSearch ? "top" : "bottom") << " start) " << (refitResult ? "succeeded" : "failed"));
255 if (refitResult) {
256 return {refitResult, kSeedRefitSuccess};
257 } else {
258 return {boundParams, kSeedRefitFailed};
259 }
260
261 }
262
263 // Function to return which 3 SPs of a seed to use
265 if (m_useLongSeeds == 2) {
266 return [](std::size_t nSp) -> std::array<std::size_t, 3> {
267 if (nSp > 3ul)
268 return {0, nSp / 2ul, nSp - 1};
269 else
270 return {0, 1, 2};
271 };
272 } else if (m_firstSp > 0ul) {
273 std::size_t firstSp = m_firstSp;
274 return [firstSp](std::size_t nSp) -> std::array<std::size_t, 3> {
275 if (nSp > 3ul) {
276 std::size_t first = std::min(firstSp, nSp - 3ul);
277 return {first, first + 1, first + 2};
278 } else
279 return {0, 1, 2};
280 };
281 } else {
282 return [](std::size_t) -> std::array<std::size_t, 3> {
283 return {0, 1, 2};
284 };
285 }
286 };
287
288
289 // Refit track. Used if refitSeeds=True.
290 std::optional<Acts::BoundTrackParameters> TrackParamsEstimationTool::doRefit(
291 const ActsTrk::Seed &measurement,
292 const Acts::BoundTrackParameters &initialParameters,
293 const Acts::GeometryContext& geometry,
294 const Acts::MagneticFieldContext& magField,
295 const Acts::CalibrationContext& calib,
296 const bool paramsAtOutermostSurface) const {
297 // Perform KF before CKF
298 const Acts::Surface* targetSurface = nullptr;
299 // get the proper surface
300 if (not paramsAtOutermostSurface) {
301 // inner-most surface
302 targetSurface = m_uncalibMeasSurfAcc.get(measurement.sp().front()->measurements().front());
303 } else {
304 // outer-most surface
305 targetSurface = m_uncalibMeasSurfAcc.get(measurement.sp().back()->measurements().back());
306 }
307 if (not targetSurface) {
308 ATH_MSG_WARNING("Could not identify the target surface for fitting the provided seed");
309 return std::nullopt;
310 }
311 const auto fittedSeedCollection = m_fitterTool->fit(measurement, initialParameters,
312 geometry, magField, calib,
313 *targetSurface);
314 if (not fittedSeedCollection) {
315 ATH_MSG_VERBOSE("KF fit failure");
316 return std::nullopt;
317 }
318 if (fittedSeedCollection->size() != 1) {
319 ATH_MSG_WARNING("KF produced " << fittedSeedCollection->size() << " tracks but should produce 1!");
320 return std::nullopt;
321 }
322 const auto fittedSeed = fittedSeedCollection->getTrack(0);
323
324 // get the track state at the beginning of the track, where we started
325 std::optional<typename decltype(fittedSeed)::ConstTrackStateProxy> trackState {std::nullopt};
326 if (paramsAtOutermostSurface) {
327 trackState = fittedSeed.outermostTrackState();
328 } else {
329 trackState = fittedSeed.innermostTrackState();
330 if (!trackState) {
331 // if the track is not forward linked (fixed by #5666), then we need to search back to the innermost track state
332 for (auto st : fittedSeed.trackStatesReversed()) {
333 trackState = st;
334 }
335 }
336 }
337
338 if (!trackState) {
339 ATH_MSG_VERBOSE("Missing "
340 << (paramsAtOutermostSurface ? "outermost" : "innermost")
341 << " track state");
342 return std::nullopt;
343 }
344
345 // Return updated parameters
346 return fittedSeed.createParametersFromState(trackState.value());
347 };
348
349}
350// namespace ActsTrk
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(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)
Definition Logger.cxx:64
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
bool estimateFromTopSp(bool reverseSearch) const override
const Acts::Logger & logger() const
Private access to the logger.
std::unique_ptr< const Acts::Logger > m_logger
logging instance
virtual std::pair< std::optional< Acts::BoundTrackParameters >, EstimationStatus > estimateTrackParameters(const ActsTrk::Seed &seed, bool reverseSearch, const Acts::GeometryContext &geoContext, const Acts::MagneticFieldContext &magFieldContext, const Acts::CalibrationContext &calContext, std::function< const Acts::Surface &(const ActsTrk::Seed &seed, bool useTopSp)> retrieveSurface) const override
std::optional< Acts::BoundTrackParameters > doRefit(const ActsTrk::Seed &measurement, const Acts::BoundTrackParameters &initialParameters, const Acts::GeometryContext &geometry, const Acts::MagneticFieldContext &magField, const Acts::CalibrationContext &calib, const bool paramsAtOutermostSurface) const
ToolHandle< ActsTrk::IFitterTool > m_fitterTool
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
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
detail::xAODUncalibMeasSurfAcc m_uncalibMeasSurfAcc
Gaudi::Property< std::size_t > m_stripCalibrationIterations
Helper class to access the Acts::surface associated with an Uncalibrated xAOD measurement.
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)
SpacePointRange sp() const noexcept