ATLAS Offline Software
Loading...
Searching...
No Matches
ExtrapolationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "ExtrapolationTool.h"
6
8
9// PACKAGE
11#include "ActsInterop/Logger.h"
12
13// ACTS
14
15#include "Acts/Geometry/VolumeBounds.hpp"
16#include "Acts/Propagator/Navigator.hpp"
17#include "Acts/Propagator/EigenStepper.hpp"
18#include "Acts/Propagator/Propagator.hpp"
19#include "Acts/Propagator/ActorList.hpp"
20#include <Acts/Propagator/StraightLineStepper.hpp>
21#include "Acts/Propagator/EigenStepperDefaultExtension.hpp"
22
23#include "Acts/Utilities/Logger.hpp"
24
25
26// STL
27#include <iostream>
28#include <memory>
29
30namespace {
31 using SteppingLogger = Acts::detail::SteppingLogger;
32 using EndOfWorld = Acts::EndOfWorldReached;
33
34 using CurvedStepper_t = Acts::EigenStepper<Acts::EigenStepperDefaultExtension>;
35 using CurvedPropagator_t = Acts::Propagator<CurvedStepper_t, Acts::Navigator>;
36 using StraightStepper_t = Acts::StraightLineStepper;
37 using StraightPropagator_t = Acts::Propagator<StraightStepper_t, Acts::Navigator>;
38
39namespace {
42 struct PassedVolumeAborter{
44 Acts::GeometryIdentifier targetVolumeId{};
47 VolumeAbort stopVolumeFlag{VolumeAbort::atExit};
48
50 explicit PassedVolumeAborter() = default;
53 template <typename propagator_state_t, typename stepper_t,
54 typename navigator_t>
55 bool checkAbort(propagator_state_t& state, const stepper_t& stepper,
56 const navigator_t& navigator, const Acts::Logger& logger) const {
58 if (targetVolumeId == Acts::GeometryIdentifier{}) {
59 ACTS_WARNING("PassedVolume aborter | Target volume not set");
60 return true;
61 }
62 const Acts::TrackingVolume* currentVolume = navigator.currentVolume(state.navigation);
63 if (currentVolume == nullptr) {
64 return false;
65 }
66
67 const Acts::Surface* surface = navigator.currentSurface(state.navigation);
69 if (surface == nullptr || surface->geometryId().boundary() == 0) {
70 return false;
71 }
72 ACTS_VERBOSE("PassedVolume - Investigate portal surface "<<surface->geometryId());
73 if (surface->geometryId().withBoundary(0) == targetVolumeId) {
74 ACTS_VERBOSE("PassedVolume - The outer boundary surface is crossed ");
75 return true;
76 }
77 if (stopVolumeFlag == VolumeAbort::atExit) {
78 return false;
79 }
81 for (const Acts::Portal& portal : currentVolume->portals()) {
82 if (portal.surface().geometryId() != surface->geometryId()) {
83 continue;
84 }
85 auto res = portal.resolveVolume(state.navigation.options.geoContext,
86 stepper.position(state.stepping),
87 stepper.direction(state.stepping));
88 if (!res.ok()) {
89 ACTS_WARNING("Failed to resolve volume through portal: "
90 << res.error().message());
91 return true;
92 }
93 return (*res)->geometryId() == targetVolumeId;
94 }
95 ACTS_WARNING("PassedVolume - Cannot find portal associated with "<<surface->geometryId());
96 return true;
97 }
98 };
99
102 struct PassedSurfaceAborter {
104 const Acts::Surface* targetSurface = nullptr;
106 double surpassedDistance{0.};
108 explicit PassedSurfaceAborter() = default;
109
112 template <typename propagator_state_t, typename stepper_t,
113 typename navigator_t>
114 bool checkAbort(propagator_state_t& state, const stepper_t& stepper,
115 const navigator_t& /*navigator*/, const Acts::Logger& logger) const {
116 if (targetSurface == nullptr) {
117 ACTS_WARNING("PassedSurfaceAborter aborter | Target surface not set.");
118 return true;
119 }
120
121 const Acts::MultiIntersection3D multiIntersection = targetSurface->intersect(state.geoContext,
122 stepper.position(state.stepping),
123 state.options.direction * stepper.direction(state.stepping),
124 Acts::BoundaryTolerance::Infinite());
125
126 const Acts::Intersection3D closestIntersection = multiIntersection.closest();
127 ACTS_VERBOSE("PassedSurfaceAborter aborter | Propagation is "<<closestIntersection.pathLength()
128 <<" away from target surface "
129 <<targetSurface->toString(state.geoContext)<<". Abort if distance is "
130 <<std::copysign(surpassedDistance, -1.)<<".");
131 return closestIntersection.pathLength() < std::copysign(surpassedDistance, -1.);
132 }
133 };
134}
135
136
137}
138
140 using VariantPropagatorBase = std::variant<CurvedPropagator_t, StraightPropagator_t>;
141
143 {
144 public:
145 using VariantPropagatorBase::VariantPropagatorBase;
146 };
147}
148
149
151
152namespace ActsTrk{
153
154
156 const std::string& name,
157 const IInterface* parent):
158 base_class{type,name, parent} {}
159
161
162StatusCode
164{
165
166
167 ATH_MSG_INFO("Initializing ACTS extrapolation");
168
169 m_logger = makeActsAthenaLogger(this, name());
170
171 ATH_CHECK( m_trackingGeometrySvc.retrieve() );
172
173 Acts::Navigator::Config navConfig{m_trackingGeometrySvc->trackingGeometry()};
174 Acts::Navigator navigator{std::move(navConfig), logger().clone()};
175
176 ATH_CHECK(m_ctxProvider.initialize());
177 if (m_fieldMode == "ATLAS") {
178 ATH_MSG_INFO("Using ATLAS magnetic field service");
179
180 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
181
182 CurvedStepper_t stepper{std::move(bField)};
183 CurvedPropagator_t propagator{std::move(stepper), std::move(navigator),
184 logger().clone()};
185 m_varProp = std::make_unique<VariantPropagator>(propagator);
186 }
187 else if (m_fieldMode == "Constant") {
188 if (m_constantFieldVector.value().size() != 3)
189 {
190 ATH_MSG_ERROR("Incorrect field vector size. Using empty field.");
191 return StatusCode::FAILURE;
192 }
193
194 Acts::Vector3 constantFieldVector = Acts::Vector3(m_constantFieldVector[0],
197
198 ATH_MSG_INFO("Using constant magnetic field: (Bx, By, Bz) = "
199 <<Amg::toString(constantFieldVector));
200
201 auto bField = std::make_shared<Acts::ConstantBField>(constantFieldVector);
202 CurvedStepper_t stepper{std::move(bField)};
203 CurvedPropagator_t propagator{std::move(stepper), std::move(navigator), logger().clone()};
204 m_varProp = std::make_unique<VariantPropagator>(propagator);
205 } else if (m_fieldMode == "StraightLine") {
206 Acts::StraightLineStepper stepper{};
207 StraightPropagator_t propagator{stepper, std::move(navigator), logger().clone()};
208 m_varProp = std::make_unique<VariantPropagator>(propagator);
209 } else {
210 ATH_MSG_FATAL("Invalid mode provided "<<m_fieldMode<<". Allowed : \"ATLAS\", \"Constant\", \"StraightLine\".");
211 return StatusCode::FAILURE;
212 }
213
214 ATH_MSG_INFO("ACTS extrapolation successfully initialized");
215 return StatusCode::SUCCESS;
216}
217
218
219Acts::Result<ExtrapolationTool::PropagationOutput>
221 const Acts::BoundTrackParameters& startParameters,
222 const Acts::Direction navDir,
223 const double pathLimit) const {
224
225 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin");
226
227 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
228 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
229
230 PropagationOutput output;
231
232 auto res = std::visit([&](const auto& propagator) -> Acts::Result<ExtrapolationTool::PropagationOutput> {
233 using Propagator = std::decay_t<decltype(propagator)>;
234
235 // Action list and abort list
236 using ActorList =
237 Acts::ActorList<SteppingLogger, Acts::MaterialInteractor, EndOfWorld>;
238 using Options = typename Propagator::template Options<ActorList>;
239
240 Options options = prepareOptions<Options>(tgContext, mfContext, startParameters, navDir, pathLimit);
241
242 auto result = propagator.propagate(startParameters, options);
243 if (!result.ok()) {
244 return result.error();
245 }
246 auto& propRes = *result;
247
248 auto steppingResults = propRes.template get<SteppingLogger::result_type>();
249 auto materialResult = propRes.template get<Acts::MaterialInteractor::result_type>();
250 output.first = std::move(steppingResults.steps);
251 output.second = std::move(materialResult);
252 // try to force return value optimization, not sure this is necessary
253 return std::move(output);
254 }, *m_varProp);
255
256 if (!res.ok()) {
257 ATH_MSG_DEBUG("Got error during propagation: "
258 << res.error() << " " << res.error().message()
259 << ". Returning empty step vector.");
260 return res.error();
261 }
262 output = std::move(*res);
263
264 ATH_MSG_VERBOSE("Collected " << output.first.size() << " steps");
265 if(output.first.size() == 0) {
266 ATH_MSG_WARNING("ZERO steps returned by stepper, that is not typically a good sign");
267 }
268
269 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " end");
270
271 return output;
272}
273
274
275
276Acts::Result<Acts::BoundTrackParameters>
277 ExtrapolationTool::propagate(const EventContext& ctx,
278 const Acts::BoundTrackParameters& startParameters,
279 const Acts::Direction navDir,
280 const double pathLimit) const
281{
282 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin");
283
284 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
285 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
286
287 auto parameters = std::visit([&](const auto& propagator) -> Acts::Result<Acts::BoundTrackParameters> {
288 using Propagator = std::decay_t<decltype(propagator)>;
289
290 // Action list and abort list
291 using ActorList =
292 Acts::ActorList<Acts::MaterialInteractor, EndOfWorld>;
293 using Options = typename Propagator::template Options<ActorList>;
294
295 Options options = prepareOptions<Options>(tgContext, mfContext, startParameters, navDir, pathLimit);
296
297
298 auto result = propagator.propagate(startParameters, options);
299 if (!result.ok()) {
300 ATH_MSG_DEBUG("Got error during propagation:" << result.error());
301 return result.error();
302 }
303 if (!result.value().endParameters.has_value()) {
304 ATH_MSG_DEBUG("Propagation did not result in valid end parameters.");
305 return Acts::PropagatorError::Failure;
306 }
307 return result.value().endParameters.value();
308 }, *m_varProp);
309
310 return parameters;
311}
312
313Acts::Result<ExtrapolationTool::PropagationOutput>
314 ExtrapolationTool::propagationSteps(const EventContext& ctx,
315 const Acts::BoundTrackParameters& startParameters,
316 const Acts::Surface& target,
317 const Acts::Direction navDir,
318 const double pathLimit) const {
319 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin");
320
321 PropagationOutput output;
322
323 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
324 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
325
326 auto res = std::visit([&](const auto& propagator) -> Acts::Result<PropagationOutput> {
327 using Propagator = std::decay_t<decltype(propagator)>;
328
329 // Action list and abort list
330 using ActorList =
331 Acts::ActorList<SteppingLogger, Acts::MaterialInteractor>;
332 using Options = typename Propagator::template Options<ActorList>;
333
334 Options options = prepareOptions<Options>(tgContext, mfContext, startParameters, navDir, pathLimit);
335 auto result = target.type() == Acts::Surface::Perigee ?
336 propagator.template propagate<Options, Acts::ForcedSurfaceReached, Acts::PathLimitReached>(startParameters, target, options) :
337 propagator.template propagate<Options, Acts::SurfaceReached, Acts::PathLimitReached>(startParameters, target, options);
338
339
340 if (!result.ok()) {
341 return result.error();
342 }
343 auto& propRes = *result;
344
345 auto steppingResults = propRes.template get<SteppingLogger::result_type>();
346 auto materialResult = propRes.template get<Acts::MaterialInteractor::result_type>();
347 output.first = std::move(steppingResults.steps);
348 output.second = std::move(materialResult);
349 return std::move(output);
350 }, *m_varProp);
351
352 if (!res.ok()) {
353 ATH_MSG_DEBUG("Got error during propagation:" << res.error()
354 << ". Returning empty step vector.");
355 return res.error();
356 }
357 output = std::move(*res);
358
359 ATH_MSG_VERBOSE("Collected " << output.first.size() << " steps");
360 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " end");
361
362 return output;
363}
364
365Acts::Result<Acts::BoundTrackParameters>
366 ExtrapolationTool::propagate(const EventContext& ctx,
367 const Acts::BoundTrackParameters& startParameters,
368 const Acts::Surface& target,
369 const Acts::Direction navDir, const double pathLimit) const
370{
371
372 ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin");
373
374 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
375 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
376
377 auto parameters = std::visit([&](const auto& propagator) -> Acts::Result<Acts::BoundTrackParameters> {
378 using Propagator = std::decay_t<decltype(propagator)>;
379
380 // Action list and abort list
381 using ActorList =
382 Acts::ActorList<Acts::MaterialInteractor>;
383 using Options = typename Propagator::template Options<ActorList>;
384
385 Options options = prepareOptions<Options>(tgContext, mfContext, startParameters, navDir, pathLimit);
386 auto result = target.type() == Acts::Surface::Perigee ?
387 propagator.template propagate<Options, Acts::ForcedSurfaceReached, Acts::PathLimitReached>(startParameters, target, options) :
388 propagator.template propagate<Options, Acts::SurfaceReached, Acts::PathLimitReached>(startParameters, target, options);
389 if (!result.ok()) {
390 ATH_MSG_DEBUG("Got error during propagation: " << result.error());
391 return result.error();
392 }
393 if (!result.value().endParameters.has_value()) {
394 ATH_MSG_DEBUG("Propagation did not result in valid end parameters.");
395 return Acts::PropagatorError::Failure;
396 }
397 return result.value().endParameters.value();
398 }, *m_varProp);
399
400 return parameters;
401}
402
403
404template<typename OptionsType>
405OptionsType ExtrapolationTool::prepareOptions(const Acts::GeometryContext& gctx,
406 const Acts::MagneticFieldContext& mfContext,
407 const Acts::BoundTrackParameters& startParameters,
408 Acts::Direction navDir, double pathLimit) const {
409 using namespace Acts::UnitLiterals;
410 OptionsType options(gctx, mfContext);
411
412 options.pathLimit = pathLimit;
413 options.loopProtection
414 = (Acts::VectorHelpers::perp(startParameters.momentum())
415 < m_ptLoopers * 1_MeV);
416 options.maxSteps = m_maxStep;
417 options.direction = navDir;
418 options.stepping.maxStepSize = m_maxStepSize * 1_m;
419 options.maxTargetSkipping = m_maxSurfSkip;
420 options.surfaceTolerance = m_surfTolerance;
421 auto& mInteractor = options.actorList.template get<Acts::MaterialInteractor>();
422 mInteractor.multipleScattering = m_interactionMultiScatering;
423 mInteractor.energyLoss = m_interactionEloss;
424 mInteractor.recordInteractions = m_interactionRecord;
425 return options;
426}
427
428Acts::Result<ExtrapolationTool::BoundParamVec_t>
430 const Acts::BoundTrackParameters& startParameters,
431 const SurfaceRecordOptions& recordOpts) const {
432
433 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
434 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
435
436 return std::visit([&](const auto& propagator) -> Acts::Result<BoundParamVec_t> {
437 using Propagator = std::decay_t<decltype(propagator)>;
438
439 // Action list and abort list
440 using ParamRecorder_t = Acts::BoundParameterRecorder<Acts::SurfaceSelector>;
441 return std::visit([&](const auto target) -> Acts::Result<BoundParamVec_t> {
442 using Target_t = std::decay_t<decltype(target)>;
443
444 using TargetAborter_t = std::conditional_t<std::is_same_v<Target_t, const Acts::Surface*>,
445 PassedSurfaceAborter, PassedVolumeAborter>;
446
447 using ActorList = Acts::ActorList<ParamRecorder_t, Acts::MaterialInteractor,
448 TargetAborter_t, EndOfWorld>;
449
450 using Options = typename Propagator::template Options<ActorList>;
451
452 auto propOptions = prepareOptions<Options>(tgContext, mfContext, startParameters,
453 recordOpts.navDir, recordOpts.pathLimit);
454
455 auto& surfaceRecorder = propOptions.actorList.template get<ParamRecorder_t>();
456 surfaceRecorder.selector.selectSensitive = recordOpts.recordSensitive;
457 surfaceRecorder.selector.selectMaterial = recordOpts.recordMaterial;
458 surfaceRecorder.selector.selectPassive = recordOpts.recordPassive;
459
460 auto& aborter = propOptions.actorList.template get<TargetAborter_t>();
461 if constexpr(std::is_same_v<Target_t, const Acts::Surface*>) {
462 aborter.targetSurface = target;
463 aborter.surpassedDistance = recordOpts.extraPathLength;
464 } else {
467 aborter.targetVolumeId = target->geometryId();
468 aborter.stopVolumeFlag = recordOpts.stopVolumeFlag;
469 }
471 auto propResult = propagator.propagate(startParameters, propOptions);
472 if (!propResult.ok()) {
473 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Propagation failed.");
474 return Acts::Result<BoundParamVec_t>::failure(std::make_error_code(std::errc::invalid_argument));
475 }
476 auto& result = *propResult;
477 return Acts::Result<BoundParamVec_t>::success(std::move(result.template get<BoundParamVec_t>()));
478 }, recordOpts.target);
479 }, *m_varProp);
480 }
481
482 Acts::Result<Acts::BoundTrackParameters> ExtrapolationTool::propagate(const EventContext& ctx,
483 const Acts::BoundTrackParameters& startParameters,
484 const Acts::TrackingVolume& target,
485 const VolumeAbort stopVolumeFlag,
486 const Acts::Direction navDir,
487 const double pathLimit) const {
488 const Acts::MagneticFieldContext mfContext = m_ctxProvider.getMagneticFieldContext(ctx);
489 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
490
491 return std::visit([&](const auto& propagator) -> Acts::Result<Acts::BoundTrackParameters> {
492 using Propagator = std::decay_t<decltype(propagator)>;
493 using ActorList = Acts::ActorList<Acts::MaterialInteractor, PassedVolumeAborter, EndOfWorld>;
494
495 using Options = typename Propagator::template Options<ActorList>;
496
497 auto propOptions = prepareOptions<Options>(tgContext, mfContext, startParameters,
498 navDir, pathLimit);
499
500 auto& aborter = propOptions.actorList.template get<PassedVolumeAborter>();
501 aborter.targetVolumeId = target.geometryId();
502 aborter.stopVolumeFlag = stopVolumeFlag;
503
505 auto propResult = propagator.propagate(startParameters, propOptions);
506 if (!propResult.ok()) {
507 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Propagation failed.");
508 return Acts::PropagatorError::Failure;
509 }
510 if (!propResult.ok()) {
511 ATH_MSG_DEBUG("Got error during propagation: " << propResult.error());
512 return propResult.error();
513 }
514 if (!propResult.value().endParameters.has_value()) {
515 ATH_MSG_DEBUG("Propagation did not result in valid end parameters.");
516 return Acts::PropagatorError::Failure;
517 }
518 return propResult.value().endParameters.value();
519 }, *m_varProp);
520 }
521}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::pair< std::vector< unsigned int >, bool > res
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
std::unique_ptr< const Acts::Logger > m_logger
Gaudi::Property< unsigned > m_maxSurfSkip
Gaudi::Property< std::vector< double > > m_constantFieldVector
const Acts::Logger & logger() const
virtual Acts::Result< PropagationOutput > propagationSteps(const EventContext &ctx, const Acts::BoundTrackParameters &startParameters, const Acts::Direction navDir, const double pathLimit) const override final
Extrapolate the track parameters until the end of the world and record the performed steps & the allo...
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
ExtrapolationTool(const std::string &type, const std::string &name, const IInterface *parent)
Explicitly define the constrcutor due to the variant forward declaration.
ContextUtility m_ctxProvider
Utility to fetch the geometry, magnetic field and calibration context in the event.
std::unique_ptr< const ActsExtrapolationDetail::VariantPropagator > m_varProp
Gaudi::Property< bool > m_interactionRecord
OptionsType prepareOptions(const Acts::GeometryContext &gctx, const Acts::MagneticFieldContext &mctx, const Acts::BoundTrackParameters &startParameters, Acts::Direction navDir, double pathLimit) const
Gaudi::Property< double > m_ptLoopers
virtual Acts::Result< Acts::BoundTrackParameters > propagate(const EventContext &ctx, const Acts::BoundTrackParameters &startParameters, const Acts::Direction navDir, const double pathLimit) const override final
Extrapolates the track parameters from a start to a target surface and returns the extrapolated track...
Gaudi::Property< std::string > m_fieldMode
Gaudi::Property< bool > m_interactionMultiScatering
Gaudi::Property< double > m_maxStepSize
Gaudi::Property< double > m_surfTolerance
Gaudi::Property< bool > m_interactionEloss
~ExtrapolationTool()
Destructor needs to implemented due to the variant.
Gaudi::Property< unsigned > m_maxStep
virtual StatusCode initialize() override
virtual Acts::Result< BoundParamVec_t > propagateAndRecord(const EventContext &ctx, const Acts::BoundTrackParameters &startParameters, const SurfaceRecordOptions &recordOpts) const override
Propagate the track parameters forward throuht the detector and record the surface crossings along th...
VolumeAbort
Enumeration to define at which stage the propagation shall be terminated.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
static Root::TMsgLogger logger("iLumiCalc")
std::variant< CurvedPropagator_t, StraightPropagator_t > VariantPropagatorBase
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.