ATLAS Offline Software
Loading...
Searching...
No Matches
Extrapolator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
6// Extrapolator.cxx, (c) ATLAS Detector software
8
12//
14//
16#include "TrkTrack/Track.h"
17//
19//
21//
24//
26//
30#include "TrkGeometry/Layer.h"
34//
37//
44//
47#include "TrkVolumes/Volume.h"
48//
51//
52#include <utility>
53#include <cstdint>
54#include <memory>
55
56
57namespace {
58 // helper class to increment and decrement the recursion level and keep
59 // track of the maximum.
60 class RecursionCounter {
61 public:
62 RecursionCounter(std::array<unsigned short,Trk::Cache::kNRecursionValues> &the_counter)
63 : m_counter(&the_counter)
64 {
67 }
68 ~RecursionCounter() { --(*m_counter)[Trk::Cache::kCurrentRecursionCount]; }
69 private:
70 std::array<unsigned short,Trk::Cache::kNRecursionValues> *m_counter;
71 };
72}
73
74namespace {
75constexpr double s_distIncreaseTolerance = 100. * Gaudi::Units::millimeter;
76constexpr unsigned int INVALIDPROPAGATORS = Trk::NumberOfSignatures+3;
77
81int
82radialDirection(const Trk::TrackParameters& pars, Trk::PropDirection dir)
83{
84 // safe inbound/outbound estimation
85 const double prePositionR = pars.position().perp();
86
87 return (prePositionR > (pars.position() + dir * 0.5 * prePositionR *
88 pars.momentum().normalized())
89 .perp())
90 ? -1
91 : 1;
92}
93std::string
94layerRZoutput(const Trk::Layer& lay)
95{
96 std::stringstream outStream;
97
98 outStream << "[r,z] = [ " << lay.surfaceRepresentation().bounds().r() << ", "
99 << lay.surfaceRepresentation().center().z() << " ] - Index ";
100 outStream << lay.layerIndex().value();
101 return outStream.str();
102}
103std::string
104momentumOutput(const Amg::Vector3D& mom)
105{
106 std::stringstream outStream;
107
108 outStream << "[eta,phi] = [ " << mom.eta() << ", " << mom.phi() << " ]";
109 return outStream.str();
110}
111
112} // end of anonymous namespace
113
114
115// constructor
116Trk::Extrapolator::Extrapolator(const std::string& t, const std::string& n, const IInterface* p)
120 , m_numOfValidPropagators(INVALIDPROPAGATORS)
121{
122 declareInterface<IExtrapolator>(this);
123}
124
125// destructor
127
128// Athena standard methods
129// initialize
130StatusCode
132{
133
134 m_referenceSurface = std::make_unique<Trk::PlaneSurface>(Amg::Transform3D(Trk::s_idTransform), 0., 0.);
135 m_referenceSurface->setOwner(Trk::userOwn); //this is owned by an instance of this class
136
139
140 // before we start messing around, how many of these updaters were actually passed in?
141 const auto numberOfSubPropagatorsGiven = m_propNames.size();
142 const auto numberOfSubMatEffUpdatersGiven = m_updatNames.size();
143 //
144 if (m_propagators.empty()) {
145 m_propagators.push_back("Trk::RungeKuttaPropagator/DefaultPropagator");
146 }
147 if (m_updaters.empty()) {
148 m_updaters.push_back("Trk::MaterialEffectsUpdator/DefaultMaterialEffectsUpdator");
149 }
150
151
152 if (!m_propagators.empty()) {
153 ATH_CHECK(m_propagators.retrieve());
154 }
155
156 // from the number of retrieved propagators set the configurationLevel
157 const unsigned int validprop = m_propagators.size();
158
159 if (!validprop) {
160 ATH_MSG_WARNING("None of the defined propagators could be retrieved!");
161 ATH_MSG_WARNING("Extrapolator unconfigured");
162 } else {
163 m_numOfValidPropagators = validprop ;
164 ATH_MSG_VERBOSE("Number of Valid Propagators " << m_numOfValidPropagators);
165 }
166
167 // Get the Navigation AlgTools
168 ATH_CHECK(m_navigator.retrieve());
169
170 // Get the Material Updator
171 if (m_includeMaterialEffects && not m_updaters.empty()) {
172 ATH_CHECK(m_updaters.retrieve());
173 for (auto& tool : m_updaters) {
174 // @TODO tools, that are already used, should not be disabled. Those are
175 // currently disabled to silence the warning issued by the tool usage
176 // detection, which is circumvented in case of the m_updaters.
177 tool.disable();
178 }
179 }
180
181 // from the number of retrieved propagators set the configurationLevel
182 const unsigned int validmeuts = m_updaters.size();
183 std::vector<std::string> fullPropagatorNames(m_propagators.size());
184 std::vector<std::string> fullUpdatorNames(m_updaters.size());
185 auto extractNameFromTool = [](const auto& toolHndl) { return toolHndl->name(); };
186 std::transform(
187 m_propagators.begin(), m_propagators.end(), fullPropagatorNames.begin(), extractNameFromTool);
188 std::transform(
189 m_updaters.begin(), m_updaters.end(), fullUpdatorNames.begin(), extractNameFromTool);
190
191 // ------------------------------------
192 // Sanity check 1
193 if (m_propNames.empty() && not m_propagators.empty()) {
195 "Inconsistent setup of Extrapolator, no sub-propagators configured, doing it for you. ");
196 m_propNames.value().push_back(TrkExTools::getToolSuffix(fullPropagatorNames[0]));
198 TrkExTools::numberOfUniqueEntries(fullPropagatorNames)) {
199 ATH_MSG_ERROR("Some configured propagators have same name but different owners");
200 }
201 if (const auto& errMsg = TrkExTools::possibleToolNameError(m_propNames); not errMsg.empty()) {
202 ATH_MSG_ERROR(errMsg);
203 }
204 }
205
206 if (m_updatNames.empty() && not m_updaters.empty()) {
207 ATH_MSG_DEBUG("Inconsistent setup of Extrapolator, no sub-material updaters configured, doing "
208 "it for you. ");
209 m_updatNames.value().push_back(TrkExTools::getToolSuffix(fullUpdatorNames[0]));
211 TrkExTools::numberOfUniqueEntries(fullUpdatorNames)) {
212 ATH_MSG_ERROR("Some configured material updaters have same name but different owners");
213 }
214 if (const auto& errMsg = TrkExTools::possibleToolNameError(m_updatNames); not errMsg.empty()) {
215 ATH_MSG_ERROR(errMsg);
216 }
217 }
218
219 // ------------------------------------
220 // Sanity check 2
221 // fill the number of propagator names and updator names up with first one
222 m_propNames.value().resize(static_cast<int>(Trk::NumberOfSignatures), m_propNames[0]);
223 m_updatNames.value().resize(static_cast<int>(Trk::NumberOfSignatures), m_updatNames[0]);
224
225 if (validprop && validmeuts) {
226 // Per definition: if configured not found, take the lowest one
227 for (unsigned int isign = 0; int(isign) < int(Trk::NumberOfSignatures); ++isign) {
228 unsigned int index = 0;
229 for (unsigned int iProp = 0; iProp < m_propagators.size(); iProp++) {
230 const std::string pname = TrkExTools::getToolSuffix(m_propagators[iProp]->name());
231 if (m_propNames[isign] == pname) {
232 index = iProp;
233 }
234 }
236 " subPropagator:" << isign << " pointing to propagator: " << m_propagators[index]->name());
237 m_subPropagators[isign] =
238 (index < validprop) ? &(*m_propagators[index]) : &(*m_propagators[Trk::Global]);
239
240 index = 0;
241 for (unsigned int iUp = 0; iUp < m_updaters.size(); iUp++) {
242 const std::string uname = TrkExTools::getToolSuffix(m_updaters[iUp]->name());
243 if (m_updatNames[isign] == uname) {
244 index = iUp;
245 }
246 }
247 ATH_MSG_DEBUG(" subMEUpdator:" << isign
248 << " pointing to updator: " << m_updaters[index]->name());
249 m_subupdaters[isign] =
250 (index < validmeuts) ? &(*m_updaters[index]) : &(*m_updaters[Trk::Global]);
251 }
252 } else {
254 "Configuration Problem of Extrapolator: "
255 << " -- At least one IPropagator and IMaterialUpdator instance have to be given.! ");
256 }
257 const std::string propStr = std::to_string(numberOfSubPropagatorsGiven) + " propagator" +
258 std::string((numberOfSubPropagatorsGiven == 1) ? "" : "s");
259 const std::string updStr = std::to_string(numberOfSubMatEffUpdatersGiven) + " updater" +
260 std::string((numberOfSubMatEffUpdatersGiven == 1) ? "" : "s");
261 std::string msgString{ "\nThe extrapolator uses six sub-propagators and "
262 "sub-material effects updaters:\n" };
263 msgString += propStr + " and " + updStr + " were given in the configuration,\n";
264 msgString += "the extrapolator sub-tools have been defined as follows: \n";
265 for (int i(0); i != int(Trk::NumberOfSignatures); ++i) {
266 msgString += std::to_string(i) + ") propagator: " + m_subPropagators[i]->name() +
267 ", updater: " + m_subupdaters[i]->name() + "\n";
268 }
269 ATH_MSG_VERBOSE(msgString);
270 ATH_CHECK(m_stepPropagator.retrieve());
271 ATH_MSG_DEBUG("initialize() successful");
272 return StatusCode::SUCCESS;
273}
274
275// finalize
276StatusCode
278{
279 if (m_propStat.m_maxRecursionCount>0) {
280 ATH_MSG_INFO("ExtrapolatorStat: maximum-recursion-depth = " << m_propStat.m_maxRecursionCount);
281 }
282 if (m_propStat.m_maxPropagations>0) {
283 ATH_MSG_INFO("ExtrapolatorStat: maximum-number-of-propagations = " << m_propStat.m_maxPropagations);
284 }
285 if (m_propStat.m_maxMethodSequence>0) {
286 ATH_MSG_INFO("ExtrapolatorStat: maximum-method-sequence-number = " << m_propStat.m_maxMethodSequence);
287 }
289 ATH_MSG_INFO(" Perfomance Statistics : ");
290 ATH_MSG_INFO(" [P] Method Statistics ------- ------------------------------------");
291 ATH_MSG_INFO(" -> Number of extrapolate() calls : " << m_extrapolateCalls);
293 " -> Number of extrapolateBlindly() calls : " << m_extrapolateBlindlyCalls);
295 " -> Number of extrapolateDirectly() calls : " << m_extrapolateDirectlyCalls);
297 " -> Number of extrapolateStepwise() calls : " << m_extrapolateStepwiseCalls);
298 ATH_MSG_INFO(" -> Number of layers switched in layer2layer : " << m_layerSwitched);
299 ATH_MSG_INFO("[P] Navigation Initialization -------------------------------------");
301 " -> Number of start associations : " << m_startThroughAssociation);
302 ATH_MSG_INFO(" -> Number of start recalls : " << m_startThroughRecall);
304 " -> Number of start global searches : " << m_startThroughGlobalSearch);
306 " -> Number of destination associations : " << m_destinationThroughAssociation);
308 " -> Number of destination recalls : " << m_destinationThroughRecall);
309 ATH_MSG_INFO(" -> Number of destination global searches : "
311 ATH_MSG_INFO("[P] Navigation Breaks ---------------------------------------------");
313 " -> Number of navigation breaks: loop : " << m_navigationBreakLoop);
315 " -> Number of navigation breaks: oscillation : " << m_navigationBreakOscillation);
317 " -> Number of navigation breaks: no volume found : " << m_navigationBreakNoVolume);
319 " -> Number of navigation breaks: dist. increase : " << m_navigationBreakDistIncrease);
320 ATH_MSG_INFO(" -> Number of navigation breaks: dist. increase : "
323 ATH_MSG_DEBUG(" Detailed output for Navigation breaks : ");
325 << " loops occured in the following volumes: ");
327 << " oscillations occured in following volumes: ");
329 << " times no next volume found of volumes: ");
331 << " distance increases detected at volumes: ");
333 << " no propagator configured for volumes: ");
334 }
335 // validation of the overlap search
336 ATH_MSG_INFO("[P] Overlaps found ------------------------------------------------");
337 ATH_MSG_INFO(" -> Number of overlap Surface hit : " << m_overlapSurfaceHit);
338 ATH_MSG_INFO(" ------------------------------------------------------------------");
339 }
340
341 return StatusCode::SUCCESS;
342}
343
344//Public Extrapolate Directly public method
345std::unique_ptr<Trk::TrackParameters>
347 const Trk::TrackParameters& parm,
348 const Trk::Surface& sf,
350 const Trk::BoundaryCheck& bcheck,
351 Trk::ParticleHypothesis particle) const
352{
353 const IPropagator* currentPropagator =
354 !m_subPropagators.empty() ? m_subPropagators[Trk::Global] : nullptr;
355 if (!currentPropagator) {
356 ATH_MSG_ERROR( "[!] No default Propagator is configured !");
357 return nullptr;
358 }
360 ctx, (*currentPropagator), parm, sf, dir, bcheck, particle);
361}
362
363//Public Charged Particle Extrapolation method
364std::unique_ptr<Trk::TrackParameters>
365Trk::Extrapolator::extrapolate(const EventContext& ctx,
366 const TrackParameters& parm,
367 const Surface& sf,
368 PropDirection dir,
369 const BoundaryCheck& bcheck,
370 ParticleHypothesis particle,
371 MaterialUpdateMode matupmode,
372 Trk::ExtrapolationCache* extrapolationCache) const
373{
374 Cache cache(m_propStat);
375 // Material effect updator cache
378 return cache.m_ownedPtrs.move(extrapolateImpl(ctx, cache, clonedInput, sf,
379 dir, bcheck, particle,
380 matupmode, extrapolationCache));
381}
382
383//Public Neutral Particle Extrapolation method
384std::unique_ptr<Trk::NeutralParameters>
386 const Surface& sf,
387 PropDirection dir,
388 const BoundaryCheck& bcheck) const
389{
390 const IPropagator* currentPropagator =
391 !m_subPropagators.empty() ? m_subPropagators[Trk::Global] : nullptr;
392 if (currentPropagator) {
393 return currentPropagator->propagate(parameters, sf, dir, bcheck);
394 }
395 ATH_MSG_ERROR("[!] No default Propagator is configured !");
396 return nullptr;
397}
398
399// Public Extrapolation method with step-wise navigation
402 const Trk::TrackParameters& parm,
403 const Trk::Surface& sf,
405 const Trk::BoundaryCheck& bcheck,
406 Trk::ParticleHypothesis particle) const
407{
408
409 const IPropagator* currentPropagator =
410 !m_subPropagators.empty() ? m_subPropagators[Trk::Global] : nullptr;
411 if (currentPropagator) {
412 return extrapolateStepwiseImpl(ctx, (*currentPropagator), parm, sf, dir,
413 bcheck, particle);
414 }
416 " [!] No default Propagator is configured !");
417 return {};
418}
419
420//Public Extrapolate starting from a Trk::Track
421std::unique_ptr<Trk::TrackParameters>
423 const EventContext& ctx,
424 const Trk::Track& trk,
425 const Trk::Surface& sf,
427 const Trk::BoundaryCheck& bcheck,
429 MaterialUpdateMode matupmode,
430 Trk::ExtrapolationCache* extrapolationCache) const
431{
432 const Trk::TrackParameters* closestTrackParameters = m_navigator->closestParameters(trk, sf);
433 if (closestTrackParameters) {
434 return (extrapolate(
435 ctx, *closestTrackParameters, sf, dir, bcheck, particle, matupmode, extrapolationCache));
436 }
437 closestTrackParameters = *(trk.trackParameters()->begin());
438 if (closestTrackParameters) {
439 return (extrapolate(
440 ctx, *closestTrackParameters, sf, dir, bcheck, particle, matupmode, extrapolationCache));
441 }
442 return nullptr;
443}
444
445//Public Extrapolate Blindly
448 const Trk::TrackParameters& parm,
450 const Trk::BoundaryCheck& bcheck,
452 const Trk::Volume* boundaryVol) const
453{
454 const IPropagator* currentPropagator =
455 !m_subPropagators.empty() ? m_subPropagators[Trk::Global] : nullptr;
456
457 if (currentPropagator) {
458 Cache cache(m_propStat);
461 return extrapolateBlindlyImpl(ctx, cache, (*currentPropagator),
462 clonedInput, dir, bcheck, particle,
463 boundaryVol);
464 }
465 ATH_MSG_ERROR(" [!] No default Propagator is configured !");
466 return {};
467}
468
469//Public extrapolateM
470std::vector<const Trk::TrackStateOnSurface*>*
471Trk::Extrapolator::extrapolateM(const EventContext& ctx,
472 const TrackParameters& parm,
473 const Surface& sf,
474 PropDirection dir,
475 const BoundaryCheck& bcheck,
476 ParticleHypothesis particle,
477 Trk::ExtrapolationCache* extrapolationCache) const
478{
479
480 Cache cache(m_propStat);
481 // Material effect updator cache
483 ATH_MSG_DEBUG("C-[" << cache.m_methodSequence << "] extrapolateM()");
484 // create a new vector for the material to be collected
485 cache.m_matstates = new std::vector<const Trk::TrackStateOnSurface*>;
486 if (m_dumpCache && extrapolationCache) {
487 ATH_MSG_DEBUG(" extrapolateM pointer extrapolationCache " << extrapolationCache << " x0tot "
488 << extrapolationCache->x0tot());
489 }
490 // collect the material
492 Trk::CacheOwnedPtr<Trk::TrackParameters> parameterAtDestination =
493 extrapolateImpl(ctx, cache, clonedInput, sf, dir, bcheck, particle,
494 Trk::addNoise, extrapolationCache);
495 if (parameterAtDestination) {
496 ATH_MSG_VERBOSE(" [+] Adding the destination surface to the TSOS vector in extrapolateM() ");
497 cache.m_matstates->push_back(new TrackStateOnSurface(
498 nullptr, cache.m_ownedPtrs.move(parameterAtDestination), nullptr));
499 } else {
500 ATH_MSG_VERBOSE(" [-] Destination surface was not hit extrapolateM()");
501 }
502 // assign the temporary states
503 std::vector<const Trk::TrackStateOnSurface*>* tmpMatStates = cache.m_matstates;
504 cache.m_matstates = nullptr;
505 // retunr the material states
506 return tmpMatStates;
507}
508
509//public collectIntersection method
510std::unique_ptr<std::vector<std::pair<std::unique_ptr<Trk::TrackParameters>, int>>>
512 const EventContext& ctx,
513 const Trk::TrackParameters& parm,
516 int destination) const
517{
518 // extrapolation method intended for collection of intersections with active layers/volumes
519 // extrapolation stops at indicated geoID subdetector exit
520 Cache cache(m_propStat);
521 ++cache.m_methodSequence;
522 ATH_MSG_DEBUG("M-[" << cache.m_methodSequence << "] extrapolate(through active volumes), from "
523 << parm.position());
524 // reset the path
525 cache.m_path = 0.;
526 // initialize parameters vector
527 cache.m_identifiedParameters = std::make_unique<identifiedParameters_t>();
528 // dummy input
529 cache.m_currentStatic = nullptr;
530 const Trk::TrackingVolume* boundaryVol = nullptr;
531 // cleanup
533 // Material effect updator cache
535 // extrapolate to subdetector boundary
536 auto *cloneInput = cache.m_ownedPtrs.push(parm.uniqueClone());
538 ctx, cache, cloneInput, -1., dir, particle, boundaryVol);
539
540 while (subDetBounds) {
541 ATH_MSG_DEBUG(" Identified subdetector boundary crossing saved "
542 << positionOutput(subDetBounds->position()));
543 cache.m_identifiedParameters->push_back(std::pair<std::unique_ptr<Trk::TrackParameters>, int>(
544 subDetBounds->uniqueClone(),
546 if (cache.m_currentStatic && cache.m_currentStatic->geometrySignature() == destination) {
547 break;
548 }
550 break; // world boundary
551 }
553 ctx, cache, subDetBounds, -1., dir, particle, boundaryVol);
554 }
555 if (cache.m_identifiedParameters->empty()) {
556 return nullptr;
557 }
558 return std::move(cache.m_identifiedParameters);
559}
560
561//Public extrapolation to the next active layer
562std::pair<std::unique_ptr<Trk::TrackParameters>, const Trk::Layer*>
564 const EventContext& ctx,
565 const TrackParameters& parm,
566 PropDirection dir,
567 const BoundaryCheck& bcheck,
568 std::vector<const Trk::TrackStateOnSurface*>& material,
569 ParticleHypothesis particle,
570 MaterialUpdateMode matupmode) const
571{
572 // set propagator to the MS one - can be reset inside the next method (once
573 // volume information is there)
574 const IPropagator* currentPropagator =
575 !m_subPropagators.empty() ? m_subPropagators[Trk::MS] : nullptr;
576 if (currentPropagator) {
577 return extrapolateToNextActiveLayerMImpl(ctx, (*currentPropagator), parm,
578 dir, bcheck, material, particle,
579 matupmode);
580 }
582 " [!] No default Propagator is configured ! Please check jobOptions.");
583 return {nullptr, nullptr};
584}
585
586//Extrapolation to volume
587std::unique_ptr<Trk::TrackParameters>
589 const Trk::TrackParameters& parm,
590 const Trk::TrackingVolume& vol,
591 PropDirection dir,
592 ParticleHypothesis particle) const
593{
594 // take the volume signatrue to define the right propagator
595 const IPropagator* currentPropagator =
597 : nullptr;
598 if (currentPropagator) {
599 return (extrapolateToVolumeImpl(ctx, *currentPropagator, parm, vol, dir,
600 particle));
601 }
603 " [!] No default Propagator is configured ! Please check jobOptions.");
604 return nullptr;
605}
606
607/* Private methods
608 * Most accept a Cache struct as an argument.
609 * This is passed to them from the public/interface methods.
610 * Then it is also propagated in-between the private methods.
611 *
612 * Start with the extrapolate Implementation ones
613 */
616 const IPropagator& prop,
617 const Trk::TrackParameters& parm,
618 const Trk::Surface& sf,
620 const Trk::BoundaryCheck& bcheck,
621 Trk::ParticleHypothesis particle) const{
622
623 Cache cache(m_propStat);
624 // statistics && sequence output ----------------------------------------
626 ++cache.m_methodSequence;
627 ATH_MSG_DEBUG("F-[" << cache.m_methodSequence << "] extrapolateStepwise(...) ");
628 // initialize the return parameters vector
629 // create a new internal helper vector
631 //The m_parametersOnDetElements point to it
632 cache.m_parametersOnDetElements = &tmp;
633 // Material effect updator cache
637 // run the extrapolation
639 ctx, cache, prop, clonedInput, sf, dir, bcheck, particle);
640 // assign the return parameter and set cache.m_parametersOnDetElements = 0;
641 if (parameterOnSf) {
642 tmp.emplace_back(cache.m_ownedPtrs.move(parameterOnSf));
643 } else {
644 tmp.clear();
645 }
646 //m_parametersOnDetElements point to nullptr
647 cache.m_parametersOnDetElements = nullptr;
648 return tmp;
649}
650
651std::pair<std::unique_ptr<Trk::TrackParameters>, const Trk::Layer*>
653 const EventContext& ctx,
654 const IPropagator& prop,
655 const Trk::TrackParameters& parm,
656 PropDirection dir,
657 const BoundaryCheck& bcheck,
658 std::vector<const Trk::TrackStateOnSurface*>& material,
659 ParticleHypothesis particle,
660 MaterialUpdateMode matupmode) const
661{
662 Cache cache(m_propStat);
663 //This is needed as we need to return a Trk::Layer
664 cache.m_cacheLastMatLayer = true;
665 ++cache.m_methodSequence;
666 ATH_MSG_DEBUG("M-[" << cache.m_methodSequence << "] extrapolateToNextActiveLayerM(...) ");
667 // Material effect updator cache
669 // initialize the return parameters vector
671 //
672 const Trk::TrackingVolume* staticVol = nullptr;
673 const Trk::Surface* destSurface = nullptr;
674 const Trk::Layer* assocLayer = nullptr;
675 // initialize material collection
676 cache.m_matstates = &material;
677
678 while (currPar) {
679 assocLayer = nullptr;
681 extrapolateToNextMaterialLayer(ctx, cache, prop, currPar, destSurface,
682 staticVol, dir, bcheck, particle,
683 matupmode);
684 if (nextPar) {
685 if (cache.m_lastMaterialLayer &&
687 nextPar->position(), bcheck, m_tolerance, m_tolerance)) {
688 assocLayer = cache.m_lastMaterialLayer;
689 }
690 if (!assocLayer) {
691 ATH_MSG_ERROR(" [!] No associated layer found - at "
692 << positionOutput(nextPar->position()));
693 }
694 } else {
695 // static volume boundary ?
699 staticVol = cache.m_parametersAtBoundary.nextVolume;
701 ATH_MSG_DEBUG(" [+] Static volume boundary: continue loop over active layers in '"
702 << staticVol->volumeName() << "'.");
703 } else { // MSentrance
706 return {cache.m_ownedPtrs.move(nextPar), nullptr};
707 }
708 } else if (cache.m_parametersAtBoundary.nextParameters) { // outer boundary
711 return {cache.m_ownedPtrs.move(nextPar), nullptr};
712 }
713 }
714 currPar = nextPar;
715 if (currPar && assocLayer && assocLayer->layerType() != 0) {
716 break;
717 }
718 }
719 // reset the boundary information
721 cache.m_matstates = nullptr;
722 return {cache.m_ownedPtrs.move(currPar), assocLayer};
723}
724
727 Cache& cache,
728 const IPropagator& prop,
730 const Trk::Surface* destSurf,
731 const Trk::TrackingVolume* vol,
732 PropDirection dir,
733 const BoundaryCheck& bcheck,
734 ParticleHypothesis particle,
735 MaterialUpdateMode matupmode) const
736{
737 RecursionCounter counter(cache.m_recursionCount);
739 ATH_MSG_WARNING("Too many recursive calls of extrapolateToNextMaterialLayer: "
742 return {};
743 }
744 ++cache.m_methodSequence;
745 ATH_MSG_DEBUG("M-[" << cache.m_methodSequence << "] extrapolateToNextMaterialLayer(...) ");
747 ATH_MSG_WARNING("Too many method sequence calls of extrapolateToNextMaterialLayer: "
748 << cache.m_methodSequence);
750 return {};
751 }
752
753 // this is the core of the material loop
754 // extrapolation without target surface returns:
755 // A) trPar at next material layer
756 // B) boundary parameters (static volume boundary)
757 // if target surface:
758 // C) trPar at target surface
759 //
760
761 // initialize the return parameters
763 const Trk::TrackingVolume* staticVol = nullptr;
764 const Trk::TrackingVolume* currVol = nullptr;
765 const Trk::TrackingVolume* nextVol = nullptr;
766 std::vector<unsigned int> solutions;
767 const Trk::TrackingVolume* assocVol = nullptr;
768 // double tol = 0.001;
769 double path = 0.;
770 bool resolveActive = destSurf == nullptr;
771 if (!resolveActive && m_resolveActive) {
772 resolveActive = m_resolveActive;
773 }
774 if (cache.m_lastMaterialLayer && !cache.m_lastMaterialLayer->isOnLayer(parm->position())) {
775 cache.m_lastMaterialLayer = nullptr;
776 }
777 // set tracking geometry in cache
778 cache.setTrackingGeometry(*m_navigator, ctx);
779 if (!cache.m_highestVolume) {
781 }
782 // resolve current position
783 Amg::Vector3D gp = parm->position();
784 if (vol && vol->inside(gp, m_tolerance)) {
785 staticVol = vol;
786 } else {
787 staticVol = cache.m_trackingGeometry->lowestStaticTrackingVolume(gp);
788 const Trk::TrackingVolume* nextStatVol = nullptr;
789 if (m_navigator->atVolumeBoundary(currPar, staticVol, dir, nextStatVol, m_tolerance) &&
790 nextStatVol != staticVol) {
791 staticVol = nextStatVol;
792 }
793 }
794
795 // navigation surfaces
796 if (cache.m_navigSurfs.capacity() > m_maxNavigSurf) {
797 cache.m_navigSurfs.reserve(m_maxNavigSurf);
798 }
799 cache.m_navigSurfs.clear();
800 if (destSurf) {
801 cache.m_navigSurfs.emplace_back(destSurf, false);
802 }
803 // alignable frame volume ?
804 if (staticVol && staticVol->geometrySignature() == Trk::Calo) {
805 if (staticVol->isAlignable()) {
806 const Trk::AlignableTrackingVolume* alignTV =
807 static_cast<const Trk::AlignableTrackingVolume*>(staticVol);
808 cache.m_identifiedParameters.reset();
809 return extrapolateInAlignableTV(ctx, cache, prop, currPar, destSurf,
810 alignTV, dir, particle);
811 }
812 }
813
814 // update if new static volume
815 if (staticVol && (staticVol != cache.m_currentStatic || resolveActive != m_resolveActive)) {
816 // retrieve boundaries
817 cache.m_currentStatic = staticVol;
818 cache.retrieveBoundaries();
819
820 cache.m_detachedVols.clear();
821 cache.m_detachedBoundaries.clear();
822 cache.m_denseVols.clear();
823 cache.m_denseBoundaries.clear();
824 cache.m_layers.clear();
825 cache.m_navigLays.clear();
826
828 staticVol->confinedDetachedVolumes();
829 if (!detVols.empty()) {
830 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const>::iterator iTer = detVols.begin();
831 for (; iTer != detVols.end(); ++iTer) {
832 // active station ?
833 const Trk::Layer* layR = (*iTer)->layerRepresentation();
834 const bool active = layR && layR->layerType();
835 const auto detBounds = (*iTer)->trackingVolume()->boundarySurfaces();
836 if (active) {
837 if (resolveActive) {
838 cache.m_detachedVols.emplace_back(*iTer, detBounds.size());
839 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
840 const Trk::Surface& surf = (detBounds[ibb])->surfaceRepresentation();
841 cache.m_detachedBoundaries.emplace_back(&surf, true);
842 }
843 } else {
844 if (!m_resolveMultilayers || (*iTer)->multilayerRepresentation().empty()) {
845 cache.addOneNavigationLayer((*iTer)->trackingVolume(), layR);
846
847 } else {
848 const auto& multi = (*iTer)->multilayerRepresentation();
849 for (const auto *i : multi) {
850 cache.addOneNavigationLayer((*iTer)->trackingVolume(), i);
851 }
852 }
853 }
854 } else if (staticVol->geometrySignature() != Trk::MS ||
856 (*iTer)->name().compare((*iTer)->name().size() - 4, 4, "PERM") ==
857 0) { // retrieve
858 // inert
859 // detached
860 // objects
861 // only if
862 // needed
863 if ((*iTer)->trackingVolume()->zOverAtimesRho() != 0. &&
864 ((*iTer)->trackingVolume()->confinedDenseVolumes().empty()) &&
865 ((*iTer)->trackingVolume()->confinedArbitraryLayers().empty())) {
866 cache.m_denseVols.emplace_back((*iTer)->trackingVolume(), detBounds.size());
867
868 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
869 const Trk::Surface& surf = (detBounds[ibb])->surfaceRepresentation();
870 cache.m_denseBoundaries.emplace_back(&surf, true);
871 }
872 }
874 (*iTer)->trackingVolume()->confinedArbitraryLayers();
875 if (!(*iTer)->trackingVolume()->confinedDenseVolumes().empty() ||
876 (confLays.size() > detBounds.size())) {
877 cache.m_detachedVols.emplace_back(*iTer, detBounds.size());
878 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
879 const Trk::Surface& surf =
880 (detBounds[ibb])->surfaceRepresentation();
881 cache.m_detachedBoundaries.emplace_back(&surf, true);
882 }
883 } else if (!confLays.empty()) {
884 for (const Trk::Layer* const lIt : confLays) {
885 cache.addOneNavigationLayer((*iTer)->trackingVolume(), (lIt));
886 }
887 }
888 }
889 }
890 }
891 cache.m_denseResolved = std::pair<unsigned int, unsigned int>(cache.m_denseVols.size(),
892 cache.m_denseBoundaries.size());
893 cache.m_layerResolved = cache.m_layers.size();
894 }
895
896 cache.m_navigSurfs.insert(
897 cache.m_navigSurfs.end(), cache.m_staticBoundaries.begin(), cache.m_staticBoundaries.end());
898
899 // resolve the use of dense volumes
900 if (staticVol) {
901 cache.m_dense = (staticVol->geometrySignature() == Trk::MS && m_useMuonMatApprox) ||
903 }
904 while (currPar && staticVol && staticVol->confinedDetachedVolumes().empty()) {
905 // propagate to closest surface
906 solutions.resize(0);
907 const Trk::TrackingVolume* propagVol = cache.m_dense ? staticVol : cache.m_highestVolume;
908 ATH_MSG_DEBUG(" [+] Starting propagation (static) at " << positionOutput(currPar->position())
909 << " in '" << propagVol->volumeName()
910 << "'");
911 // current static may carry non-trivial material properties, their use is optional;
912 // use highest volume as B field source
913 std::unique_ptr<Trk::TrackParameters> pNextPar = prop.propagate(ctx,*currPar,cache.m_navigSurfs,
914 dir,m_fieldProperties,particle,solutions,path,false,
915 false,propagVol);
916 Trk::CacheOwnedPtr<Trk::TrackParameters> nextPar = cache.m_ownedPtrs.push(std::move(pNextPar));
917 if (nextPar) {
918 ++cache.m_nPropagations;
919 ATH_MSG_DEBUG(" [+] Position after propagation - at "
920 << positionOutput(nextPar->position()));
921 }
922 if (!nextPar) {
924 return {};
925 }
926 if (nextPar) {
927 // collect material
928 if (propagVol->zOverAtimesRho() != 0. && !cache.m_matstates && cache.m_extrapolationCache) {
929 if (not cache.elossPointerOverwritten()) {
930 if (m_dumpCache) {
931 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer"));
932 }
933 const double dInX0 = std::abs(path) / propagVol->x0();
934 ATH_MSG_DEBUG(" add x0 " << dInX0);
935 cache.m_extrapolationCache->updateX0(dInX0);
936 const Trk::MaterialProperties materialProperties(*propagVol, std::abs(path));
937 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
938 EnergyLoss const eloss = m_elossupdater->energyLoss(
939 materialProperties, std::abs(1. / currentqoverp), 1., dir, particle);
940 ATH_MSG_DEBUG(" [M] Energy loss: STEP,EnergyLossUpdator:"
941 << nextPar->momentum().mag() - currPar->momentum().mag() << ","
942 << eloss.deltaE());
944 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
945 if (m_dumpCache) {
946 ATH_MSG_DEBUG(cache.to_string( " After"));
947 }
948 } else {
949 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
950 }
951 }
952 if (propagVol->zOverAtimesRho() != 0. && cache.m_matstates) {
953 const double dInX0 = std::abs(path) / propagVol->x0();
954 const Trk::MaterialProperties materialProperties(*propagVol, std::abs(path));
955 const double scatsigma = std::sqrt(m_msupdater->sigmaSquare(
956 materialProperties, 1. / std::abs(nextPar->parameters()[qOverP]), 1., particle));
957 auto newsa = Trk::ScatteringAngles(
958 0, 0, scatsigma / std::sin(nextPar->parameters()[Trk::theta]), scatsigma);
959 // energy loss
960 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
961 EnergyLoss eloss = m_elossupdater->energyLoss(
962 materialProperties, std::abs(1. / currentqoverp), 1., dir, particle);
963 // compare energy loss
964 ATH_MSG_DEBUG(" [M] Energy loss: STEP,EnergyLossUpdator:"
965 << nextPar->momentum().mag() - currPar->momentum().mag() << ","
966 << eloss.deltaE());
967 // use curvilinear TPs to simplify retrieval by fitters
968 std::unique_ptr<Trk::TrackParameters> cvlTP(new Trk::CurvilinearParameters(
969 nextPar->position(), nextPar->momentum(), nextPar->charge()));
970 //
971 if (cache.m_extrapolationCache) {
972 if (m_dumpCache) {
973 ATH_MSG_DEBUG(cache.to_string( " mat states extrapolateToNextMaterialLayer"));
974 }
975 cache.m_extrapolationCache->updateX0(dInX0);
977 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
978 if (m_dumpCache) {
979 ATH_MSG_DEBUG(cache.to_string( " After"));
980 }
981 }
982 auto mefot = std::make_unique<Trk::MaterialEffectsOnTrack>(
983 dInX0, newsa, std::make_unique<Trk::EnergyLoss>(std::move(eloss)),
984 cvlTP->associatedSurface());
985 cache.m_matstates->push_back(new TrackStateOnSurface(
986 nullptr, std::move(cvlTP), std::move(mefot)));
987 ATH_MSG_DEBUG(" [M] Collecting material from static volume '" << propagVol->volumeName()
988 << "', t/X0 = " << dInX0);
989 }
990 }
991 currPar = nextPar;
992 const unsigned int isurf = destSurf ? 1 : 0;
993 if (destSurf && solutions[0] == 0) {
994 return currPar;
995 }
996 if (destSurf && solutions.size() > 1 && solutions[1] == 0) {
997 return currPar;
998 }
999 if (solutions[0] <= isurf + cache.m_staticBoundaries.size()) { // static volume boundary
1000 // use global coordinates to retrieve attached volume (just for static!)
1001 const Trk::TrackingVolume* nextVol =
1002 cache.m_currentStatic->boundarySurfaces()[solutions[0] - isurf]->attachedVolume(
1003 currPar->position(), currPar->momentum(), dir);
1004 cache.m_parametersAtBoundary.boundaryInformation(nextVol, currPar, currPar);
1005 if (!nextVol) {
1006 ATH_MSG_DEBUG(" [!] World boundary at position R,z: " << currPar->position().perp() << ","
1007 << currPar->position().z());
1008 } else {
1009 ATH_MSG_DEBUG("M-S Crossing to static volume '" << nextVol->volumeName() << "'.'");
1010 }
1011 }
1012 return {};
1013 }
1014
1015 if (!staticVol || (staticVol->confinedDetachedVolumes().empty()) || !currPar) {
1016 return {};
1017 }
1018
1019 // reset remaining counters
1020 cache.m_currentDense = cache.m_dense ? cache.m_currentStatic : cache.m_highestVolume;
1021 cache.m_navigBoundaries.clear();
1022 if (cache.m_denseVols.size() > cache.m_denseResolved.first) {
1023 cache.m_denseVols.resize(cache.m_denseResolved.first);
1024 }
1025 while (cache.m_denseBoundaries.size() > cache.m_denseResolved.second) {
1026 cache.m_denseBoundaries.pop_back();
1027 }
1028 if (cache.m_layers.size() > cache.m_layerResolved) {
1029 cache.m_navigLays.resize(cache.m_layerResolved);
1030 }
1031 while (cache.m_layers.size() > cache.m_layerResolved) {
1032 cache.m_layers.pop_back();
1033 }
1034
1035 // current detached volumes
1036 // collect : subvolume boundaries, ordered/unordered layers, confined dense volumes
1038 // const Trk::DetachedTrackingVolume* currentActive = 0;
1039 if (cache.m_navigVolsInt.capacity() > m_maxNavigVol) {
1040 cache.m_navigVolsInt.reserve(m_maxNavigVol);
1041 }
1042 cache.m_navigVolsInt.clear();
1043
1044 gp = currPar->position();
1045 std::vector<const Trk::DetachedTrackingVolume*> detVols =
1047 std::vector<const Trk::DetachedTrackingVolume*>::iterator dIter = detVols.begin();
1048 for (; dIter != detVols.end(); ++dIter) {
1049 const Trk::Layer* layR = (*dIter)->layerRepresentation();
1050 const bool active = layR && layR->layerType();
1051 if (active && !resolveActive) {
1052 continue;
1053 }
1054 if (!active && staticVol->geometrySignature() == Trk::MS && m_useMuonMatApprox &&
1055 (*dIter)->name().compare((*dIter)->name().size() - 4, 4, "PERM") != 0) {
1056 continue;
1057 }
1058 const Trk::TrackingVolume* dVol = (*dIter)->trackingVolume();
1059 // detached volume exit ?
1060 const bool dExit =
1061 m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) && !nextVol;
1062 if (dExit) {
1063 continue;
1064 }
1065 // inert material
1066 const auto confinedDense = dVol->confinedDenseVolumes();
1067 const auto confinedLays = dVol->confinedArbitraryLayers();
1068
1069 if (!active && confinedDense.empty() && confinedLays.empty()) {
1070 continue;
1071 }
1072 const auto bounds = dVol->boundarySurfaces();
1073 if (!active && confinedDense.empty() && confinedLays.size() <= bounds.size()) {
1074 continue;
1075 }
1076 if (!confinedDense.empty() || !confinedLays.empty()) {
1077 cache.m_navigVolsInt.emplace_back(dVol, bounds.size());
1078 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1079 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
1080 cache.m_navigBoundaries.emplace_back(&surf, true);
1081 }
1082 // collect dense volume boundary
1083 if (!confinedDense.empty()) {
1084 auto vIter = confinedDense.begin();
1085 for (; vIter != confinedDense.end(); ++vIter) {
1086 const auto bounds = (*vIter)->boundarySurfaces();
1087 cache.m_denseVols.emplace_back(*vIter, bounds.size());
1088 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1089 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
1090 cache.m_denseBoundaries.emplace_back(&surf, true);
1091 }
1092 }
1093 }
1094 // collect unordered layers
1095 if (!confinedLays.empty()) {
1096 for (const auto *confinedLay : confinedLays) {
1097 cache.addOneNavigationLayer(dVol, confinedLay);
1098 }
1099 }
1100 } else { // active material
1101 const Trk::TrackingVolume* detVol = dVol->associatedSubVolume(gp);
1102 if (!detVol && dVol->confinedVolumes()) {
1103 std::span<Trk::TrackingVolume const * const> const subvols = dVol->confinedVolumes()->arrayObjects();
1104 for (const auto *subvol : subvols) {
1105 if (subvol->inside(gp, m_tolerance)) {
1106 detVol = subvol;
1107 break;
1108 }
1109 }
1110 }
1111
1112 if (!detVol) {
1113 detVol = dVol;
1114 }
1115 bool vExit =
1116 m_navigator->atVolumeBoundary(currPar, detVol, dir, nextVol, m_tolerance) &&
1117 nextVol != detVol;
1118 if (vExit && nextVol && nextVol->inside(gp, m_tolerance)) {
1119 detVol = nextVol;
1120 vExit = false;
1121 }
1122 if (!vExit) {
1123 const auto bounds = detVol->boundarySurfaces();
1124 cache.m_navigVolsInt.emplace_back(detVol, bounds.size());
1125 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1126 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
1127 cache.m_navigBoundaries.emplace_back(&surf, true);
1128 }
1129 if (detVol->zOverAtimesRho() != 0.) {
1130 cache.m_denseVols.emplace_back(detVol, bounds.size());
1131 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1132 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
1133 cache.m_denseBoundaries.emplace_back(&surf, true);
1134 }
1135 }
1136 // layers ?
1137 if (detVol->confinedLayers()) {
1138 const Trk::Layer* lay = detVol->associatedLayer(gp);
1139
1140 if (lay) {
1141 cache.addOneNavigationLayer(detVol, lay);
1142
1143 }
1144 const Trk::Layer* nextLayer =
1145 detVol->nextLayer(currPar->position(), dir * currPar->momentum().unit(), true);
1146 if (nextLayer && nextLayer != lay) {
1147 cache.addOneNavigationLayer(detVol, nextLayer);
1148 }
1149 } else if (!detVol->confinedArbitraryLayers().empty()) {
1151 for (const auto *layer : layers) {
1152 cache.addOneNavigationLayer(detVol, layer);
1153 }
1154 }
1155 }
1156 }
1157 }
1159
1160 // current dense
1161 cache.m_currentDense = cache.m_highestVolume;
1162 if (cache.m_dense && cache.m_denseVols.empty()) {
1163 cache.m_currentDense = cache.m_currentStatic;
1164 } else {
1165 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
1166 const Trk::TrackingVolume* dVol = cache.m_denseVols[i].first;
1167 if (dVol->inside(currPar->position(), m_tolerance) && dVol->zOverAtimesRho() != 0.) {
1168 if (!m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) ||
1169 nextVol == dVol) {
1170 cache.m_currentDense = dVol;
1171 }
1172 }
1173 }
1174 }
1175 // ready to propagate
1176 // till: A/ static volume boundary(bcheck=true) , B/ material layer(bcheck=true), C/ destination
1177 // surface(bcheck=false) update of cache.m_navigSurfs required if I/ entry into new navig volume,
1178 // II/ exit from currentActive without overlaps
1179 nextVol = nullptr;
1180 while (currPar) {
1181 double path = 0.;
1182 std::vector<unsigned int> solutions;
1183 // verify that material input makes sense
1184 const Amg::Vector3D tp =
1185 currPar->position() + 2 * m_tolerance * dir * currPar->momentum().normalized();
1186 if (!(cache.m_currentDense->inside(tp, 0.))) {
1187 cache.m_currentDense = cache.m_highestVolume;
1188 if (cache.m_dense && cache.m_denseVols.empty()) {
1189 cache.m_currentDense = cache.m_currentStatic;
1190 } else {
1191 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
1192 const Trk::TrackingVolume* dVol = cache.m_denseVols[i].first;
1193 if (dVol->inside(tp, 0.) && dVol->zOverAtimesRho() != 0.) {
1194 cache.m_currentDense = dVol;
1195 }
1196 }
1197 }
1198 }
1199 // propagate now
1200 ATH_MSG_DEBUG(" [+] Starting propagation at position "
1201 << positionOutput(currPar->position())
1202 << " (current momentum: " << currPar->momentum().mag() << ")");
1203 ATH_MSG_DEBUG(" [+] " << cache.m_navigSurfs.size() << " target surfaces in '"
1204 << cache.m_currentDense->volumeName() << "'.");
1206 ctx, *currPar, cache.m_navigSurfs, dir, m_fieldProperties, particle,
1207 solutions, path, false, false, cache.m_currentDense));
1208 if (nextPar) {
1209 ++cache.m_nPropagations;
1210 ATH_MSG_DEBUG(" [+] Position after propagation - at "
1211 << positionOutput(nextPar->position()));
1212 }
1213 // check missing volume boundary
1214 if (nextPar && !(cache.m_currentDense->inside(nextPar->position(), m_tolerance) ||
1215 m_navigator->atVolumeBoundary(
1216 nextPar, cache.m_currentDense, dir, assocVol, m_tolerance))) {
1217 ATH_MSG_DEBUG(" [!] ERROR: missing volume boundary for volume"
1218 << cache.m_currentDense->volumeName());
1219 if (cache.m_currentDense->zOverAtimesRho() != 0.) {
1220 ATH_MSG_DEBUG(" [!] ERROR: trying to recover: repeat the propagation step in"
1221 << cache.m_highestVolume->volumeName());
1222 cache.m_currentDense = cache.m_highestVolume;
1223 continue;
1224 }
1225 }
1226 if (nextPar) {
1227 ATH_MSG_DEBUG(" [+] Number of intersection solutions: " << solutions.size());
1228 if (cache.m_currentDense->zOverAtimesRho() != 0. && !cache.m_matstates &&
1229 cache.m_extrapolationCache) {
1230 if (not cache.elossPointerOverwritten()) {
1231 if (m_dumpCache) {
1232 ATH_MSG_DEBUG(cache.to_string( " extrapolateToNextMaterialLayer dense "));
1233 }
1234 const double dInX0 = std::abs(path) / cache.m_currentDense->x0();
1235 cache.m_extrapolationCache->updateX0(dInX0);
1236 const Trk::MaterialProperties materialProperties(*cache.m_currentDense, std::abs(path));
1237 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1238 const Trk::EnergyLoss eloss = m_elossupdater->energyLoss(
1239 materialProperties, std::abs(1. / currentqoverp), 1., dir, particle);
1241 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
1242 if (m_dumpCache) {
1243 ATH_MSG_DEBUG(cache.to_string(" After"));
1244 }
1245 } else {
1246 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
1247 }
1248 }
1249 // collect material
1250 if (cache.m_currentDense->zOverAtimesRho() != 0. && cache.m_matstates) {
1251 const double dInX0 = std::abs(path) / cache.m_currentDense->x0();
1252 if (path * dir < 0.) {
1253 ATH_MSG_WARNING(" got negative path!! " << path);
1254 }
1255 const Trk::MaterialProperties materialProperties(*cache.m_currentDense, std::abs(path));
1256 const double scatsigma = std::sqrt(m_msupdater->sigmaSquare(
1257 materialProperties, 1. / std::abs(nextPar->parameters()[qOverP]), 1., particle));
1258 auto newsa = Trk::ScatteringAngles(
1259 0, 0, scatsigma / std::sin(nextPar->parameters()[Trk::theta]), scatsigma);
1260 // energy loss
1261 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1262 EnergyLoss eloss = m_elossupdater->energyLoss(
1263 materialProperties, std::abs(1. / currentqoverp), 1., dir, particle);
1264 // compare energy loss
1265 ATH_MSG_DEBUG(" [M] Energy loss: STEP,EnergyLossUpdator:"
1266 << nextPar->momentum().mag() - currPar->momentum().mag() << ","
1267 << eloss.deltaE());
1268
1269 // use curvilinear TPs to simplify retrieval by fitters
1270 std::unique_ptr<Trk::TrackParameters> cvlTP(new Trk::CurvilinearParameters(
1271 nextPar->position(), nextPar->momentum(), nextPar->charge()));
1272
1273 if (cache.m_extrapolationCache) {
1274 if (m_dumpCache) {
1275 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer dense"));
1276 }
1277 cache.m_extrapolationCache->updateX0(dInX0);
1279 eloss.sigmaIoni(),
1280 eloss.meanRad(),
1281 eloss.sigmaRad());
1282 if (m_dumpCache) {
1283 ATH_MSG_DEBUG(cache.to_string(" After"));
1284 }
1285 }
1286 auto mefot = std::make_unique<Trk::MaterialEffectsOnTrack>(
1287 dInX0, newsa, std::make_unique<Trk::EnergyLoss>(std::move(eloss)), cvlTP->associatedSurface());
1288
1289 cache.m_matstates->push_back(new TrackStateOnSurface(
1290 nullptr, std::move(cvlTP), std::move(mefot)));
1291
1292 ATH_MSG_DEBUG(" [M] Collecting material from dense volume '"
1293 << cache.m_currentDense->volumeName() << "', t/X0 = " << dInX0);
1294 }
1295 // destination surface
1296 if (destSurf && solutions[0] == 0) {
1297 return nextPar;
1298 }
1299 if (destSurf && solutions.size() > 1 && solutions[1] == 0) {
1300 return nextPar;
1301 }
1302 // destination surface missed ?
1303 if (destSurf) {
1304 double dist = 0.;
1305 const Trk::DistanceSolution distSol = destSurf->straightLineDistanceEstimate(
1306 nextPar->position(), nextPar->momentum().normalized());
1307 if (distSol.numberOfSolutions() > 0) {
1308 dist = distSol.first();
1309 if (distSol.numberOfSolutions() > 1 && std::abs(dist) < m_tolerance) {
1310 dist = distSol.second();
1311 }
1312 if (distSol.numberOfSolutions() > 1 && dist * dir < 0. && distSol.second() * dir > 0.) {
1313 dist = distSol.second();
1314 }
1315 } else {
1316 dist = distSol.toPointOfClosestApproach();
1317 }
1318 if (dist * dir < 0.) {
1319 ATH_MSG_DEBUG(" [+] Destination surface missed ? " << dist << "," << dir);
1321 return {};
1322 }
1323 ATH_MSG_DEBUG(" [+] New 3D-distance to destinatiion - d3 = " << dist * dir);
1324 }
1325
1326 int const iDest = destSurf ? 1 : 0;
1327 unsigned int iSol = 0;
1328 while (iSol < solutions.size()) {
1329 if (solutions[iSol] < iDest + cache.m_staticBoundaries.size()) {
1330 // material attached ?
1331 const Trk::Layer* mb = cache.m_navigSurfs[solutions[iSol]].first->materialLayer();
1332 if (mb) {
1333 if (mb->layerMaterialProperties() &&
1334 mb->layerMaterialProperties()->fullMaterial(nextPar->position())) {
1335
1336 const IMaterialEffectsUpdator* currentUpdator =
1338 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
1340
1341 if (currentUpdator) {
1342 nextPar = cache.m_ownedPtrs.push(
1343 currentUpdator->update(currentUpdatorCache, nextPar,
1344 *mb, dir, particle, matupmode));
1345 }
1346 if (!nextPar) {
1348 return {};
1349 }
1350
1351 // collect material
1352 const Trk::MaterialProperties* lmat = mb->fullUpdateMaterialProperties(*nextPar);
1353 const double lx0 = lmat->x0();
1354 const double layThick = mb->thickness();
1355
1356 double thick = 0.;
1357 const double costr =
1358 std::abs(nextPar->momentum().normalized().dot(mb->surfaceRepresentation().normal()));
1359
1360 if (mb->surfaceRepresentation().isOnSurface(
1361 mb->surfaceRepresentation().center(), false, 0., 0.)) {
1362 thick = fmin(mb->surfaceRepresentation().bounds().r(),
1363 layThick / std::abs(nextPar->momentum().normalized().dot(
1364 mb->surfaceRepresentation().normal())));
1365 } else {
1366 thick = fmin(2 * mb->thickness(), layThick / (1 - costr));
1367 }
1368
1369 if (!cache.m_matstates && cache.m_extrapolationCache) {
1370 if (not cache.elossPointerOverwritten()) {
1371 const double dInX0 = thick / lx0;
1372 if (m_dumpCache) {
1373 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer thin "));
1374 }
1375 cache.m_extrapolationCache->updateX0(dInX0);
1376 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1377 EnergyLoss const eloss = m_elossupdater->energyLoss(
1378 *lmat, std::abs(1. / currentqoverp), 1. / costr, dir, particle);
1380 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
1381 if (m_dumpCache) {
1382 ATH_MSG_DEBUG(cache.to_string(" After"));
1383 }
1384 } else {
1385 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
1386 }
1387
1388 }
1389
1390 if (cache.m_matstates) {
1391 const double dInX0 = thick / lx0;
1392 const double scatsigma = std::sqrt(m_msupdater->sigmaSquare(
1393 *lmat, 1. / std::abs(nextPar->parameters()[qOverP]), 1., particle));
1394 auto newsa = Trk::ScatteringAngles(
1395 0, 0, scatsigma / std::sin(nextPar->parameters()[Trk::theta]), scatsigma);
1396 // energy loss
1397 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1398 EnergyLoss eloss = m_elossupdater->energyLoss(
1399 *lmat, std::abs(1. / currentqoverp), 1. / costr, dir, particle);
1400
1401 // use curvilinear TPs to simplify retrieval by fitters
1402 std::unique_ptr<Trk::TrackParameters> cvlTP(new Trk::CurvilinearParameters(
1403 nextPar->position(), nextPar->momentum(), nextPar->charge()));
1404 if (cache.m_extrapolationCache) {
1405 if (not cache.elossPointerOverwritten()) {
1406 if (m_dumpCache) {
1407 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer thin "));
1408 }
1409 cache.m_extrapolationCache->updateX0(dInX0);
1411 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
1412 if (m_dumpCache) {
1413 ATH_MSG_DEBUG(cache.to_string(" After"));
1414 }
1415 } else {
1416 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
1417 }
1418 }
1419 auto mefot =
1420 std::make_unique<Trk::MaterialEffectsOnTrack>(
1421 dInX0, newsa,
1422 std::make_unique<Trk::EnergyLoss>(std::move(eloss)),
1423 cvlTP->associatedSurface());
1424 cache.m_matstates->push_back(new TrackStateOnSurface(
1425 nullptr, std::move(cvlTP), std::move(mefot)));
1426 }
1427 }
1428 } // end material update at massive (static volume) boundary
1429
1430 // static volume boundary; return to the main loop
1431 const unsigned int index = solutions[iSol] - iDest;
1432 // use global coordinates to retrieve attached volume (just for static!)
1433 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
1434 nextPar->position(), nextPar->momentum(), dir);
1435 // double check the next volume
1436 if (nextVol &&
1437 !(nextVol->inside(nextPar->position() + 0.01 * dir * nextPar->momentum().normalized(),
1438 m_tolerance))) {
1439 ATH_MSG_DEBUG(" [!] WARNING: wrongly assigned static volume ?"
1440 << cache.m_currentStatic->volumeName() << "->" << nextVol->volumeName());
1442 nextPar->position() + 0.01 * nextPar->momentum().normalized());
1443 if (nextVol) {
1444 ATH_MSG_DEBUG(" new search yields: " << nextVol->volumeName());
1445 }
1446 }
1447 // end double check - to be removed after validation of the geometry gluing
1448 if (nextVol != cache.m_currentStatic) {
1449 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
1450 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '"
1451 << cache.m_currentStatic->volumeName() << "'.");
1452 if (m_navigator->atVolumeBoundary(
1453 nextPar, cache.m_currentStatic, dir, assocVol, m_tolerance) &&
1454 assocVol != cache.m_currentStatic) {
1455 cache.m_currentDense = m_useMuonMatApprox ? nextVol : cache.m_highestVolume;
1456 }
1457 // no next volume found --- end of the world
1458 if (!nextVol) {
1459 ATH_MSG_DEBUG(" [+] Word boundary reached - at "
1460 << positionOutput(nextPar->position()));
1461 }
1462 // next volume found and parameters are at boundary
1463 if (nextVol && nextPar) {
1464 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
1465 ATH_MSG_DEBUG(" [+] Crossing position is - at "
1466 << positionOutput(nextPar->position()));
1467 }
1468 return {};
1469 }
1470 } else if (solutions[iSol] <
1471 iDest + cache.m_staticBoundaries.size() + cache.m_layers.size()) {
1472 // next layer; don't return passive material layers unless required
1473 const unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size();
1474 const Trk::Layer* nextLayer = cache.m_navigLays[index].second;
1475 // material update HERE and NOW (pre/post udpdate ? )
1476 // don't repeat if identical to last update && input parameters on the layer
1477 bool collect = true;
1478 if (nextLayer == cache.m_lastMaterialLayer &&
1481 " [!] This layer is identical to the one with last material update, return layer "
1482 "without repeating the update");
1483 collect = false;
1484 if (!destSurf && (nextLayer->layerType() > 0)) {
1485 return nextPar;
1486 }
1487 }
1488 const double layThick = nextLayer->thickness();
1489 if (collect && layThick > 0.) { // collect material
1490
1491 // get the right updator
1492 const IMaterialEffectsUpdator* currentUpdator =
1494 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
1496
1497 if (currentUpdator) {
1498 nextPar = cache.m_ownedPtrs.push(
1499 currentUpdator->update(currentUpdatorCache, nextPar,
1500 *nextLayer, dir, particle, matupmode));
1501 }
1502 if (!nextPar) {
1504 return {};
1505 }
1506
1507 // collect material
1508 const double lx0 = nextLayer->fullUpdateMaterialProperties(*nextPar)->x0();
1509
1510 double thick = 0.;
1511 const double costr = std::abs(
1512 nextPar->momentum().normalized().dot(nextLayer->surfaceRepresentation().normal()));
1513
1514 if (nextLayer->surfaceRepresentation().isOnSurface(
1515 nextLayer->surfaceRepresentation().center(), false, 0., 0.)) {
1516 thick = fmin(nextLayer->surfaceRepresentation().bounds().r(),
1517 layThick / std::abs(nextPar->momentum().normalized().dot(
1518 nextLayer->surfaceRepresentation().normal())));
1519 } else {
1520 thick = fmin(2 * nextLayer->thickness(), layThick / (1 - costr));
1521 }
1522
1523 if (!cache.m_matstates && cache.m_extrapolationCache) {
1524 if (not cache.elossPointerOverwritten()) {
1525 const double dInX0 = thick / lx0;
1526 if (m_dumpCache) {
1527 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer thin "));
1528 }
1529 cache.m_extrapolationCache->updateX0(dInX0);
1530 const Trk::MaterialProperties materialProperties(
1531 *nextLayer->fullUpdateMaterialProperties(*nextPar)); // !<@TODO check
1532 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1533 EnergyLoss const eloss = m_elossupdater->energyLoss(
1534 materialProperties, std::abs(1. / currentqoverp), 1. / costr, dir, particle);
1536 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
1537 if (m_dumpCache) {
1538 ATH_MSG_DEBUG(cache.to_string( " After"));
1539 }
1540 } else {
1541 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
1542 }
1543 }
1544
1545 if (cache.m_matstates) {
1546 const double dInX0 = thick / lx0;
1547 const Trk::MaterialProperties materialProperties(
1548 *nextLayer->fullUpdateMaterialProperties(*nextPar)); // !<@TODOcheck
1549 const double scatsigma = std::sqrt(m_msupdater->sigmaSquare(
1550 materialProperties, 1. / std::abs(nextPar->parameters()[qOverP]), 1., particle));
1551 const double par_theta = std::abs(nextPar->parameters()[Trk::theta]) > FLT_EPSILON
1552 ? nextPar->parameters()[Trk::theta]
1553 : FLT_EPSILON;
1554 Trk::ScatteringAngles newsa(0, 0, scatsigma / std::sin(par_theta), scatsigma);
1555 // energy loss
1556 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
1557 EnergyLoss eloss = m_elossupdater->energyLoss(
1558 materialProperties, std::abs(1. / currentqoverp), 1. / costr, dir, particle);
1559
1560 // use curvilinear TPs to simplify retrieval by fitters
1561 auto cvlTP = std::make_unique<Trk::CurvilinearParameters>(
1562 nextPar->position(), nextPar->momentum(), nextPar->charge());
1563 if (cache.m_extrapolationCache) {
1564 if (not cache.elossPointerOverwritten()) {
1565 if (m_dumpCache) {
1566 ATH_MSG_DEBUG(cache.to_string(" extrapolateToNextMaterialLayer thin "));
1567 }
1568 cache.m_extrapolationCache->updateX0(dInX0);
1570 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
1571 if (m_dumpCache) {
1572 ATH_MSG_DEBUG(cache.to_string( " After"));
1573 }
1574 } else {
1575 ATH_MSG_DEBUG(cache.elossPointerErrorMsg(__LINE__));
1576 }
1577 }
1578 auto mefot = std::make_unique<Trk::MaterialEffectsOnTrack>(
1579 dInX0, newsa, std::make_unique<Trk::EnergyLoss>(std::move(eloss)), cvlTP->associatedSurface());
1580 cache.m_matstates->push_back(new TrackStateOnSurface(
1581 nullptr, std::move(cvlTP), std::move(mefot)));
1582 }
1583 //
1584 if (cache.m_cacheLastMatLayer) {
1585 cache.m_lastMaterialLayer = nextLayer;
1586 }
1587 if (!destSurf && nextLayer->layerType() > 0) {
1588 return nextPar;
1589 }
1590 }
1591 if (resolveActive) {
1592 // if ordered layers, retrieve the next layer and replace the current one in the list
1593 if (cache.m_navigLays[index].first &&
1594 cache.m_navigLays[index].first->confinedLayers()) {
1595 const Trk::Layer* newLayer = cache.m_navigLays[index].first->nextLayer(
1596 nextPar->position(), dir * nextPar->momentum().normalized(), true);
1597 if (newLayer) {
1598 cache.m_navigLays[index].second = newLayer;
1599 cache.m_navigSurfs[solutions[iSol]].first = &(newLayer->surfaceRepresentation());
1600 }
1601 }
1602 }
1603 // not necessary: currPar = nextPar; since done outside the loop and currPar not used
1604 // inside the loop
1605 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() +
1606 cache.m_layers.size() + cache.m_denseBoundaries.size()) {
1607 // dense volume boundary
1608 unsigned int index =
1609 solutions[iSol] - iDest - cache.m_staticBoundaries.size() - cache.m_layers.size();
1610 std::vector<std::pair<const Trk::TrackingVolume*, unsigned int>>::iterator dIter =
1611 cache.m_denseVols.begin();
1612 while (dIter != cache.m_denseVols.end() && index >= (*dIter).second) {
1613 index -= (*dIter).second;
1614 ++dIter;
1615 }
1616 if (dIter != cache.m_denseVols.end()) {
1617 currVol = (*dIter).first;
1618 nextVol =
1619 ((*dIter).first->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
1620 // boundary orientation not reliable
1621 const Amg::Vector3D tp =
1622 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
1623 if (currVol->inside(tp, m_tolerance)) {
1624 cache.m_currentDense = currVol;
1625 } else if (!nextVol || !nextVol->inside(tp, m_tolerance)) { // search for dense volumes
1626 cache.m_currentDense = cache.m_highestVolume;
1627 if (cache.m_dense && cache.m_denseVols.empty()) {
1628 cache.m_currentDense = cache.m_currentStatic;
1629 } else {
1630 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
1631 const Trk::TrackingVolume* dVol = cache.m_denseVols[i].first;
1632 if (dVol->inside(tp, 0.) && dVol->zOverAtimesRho() != 0.) {
1633 cache.m_currentDense = dVol;
1634 ATH_MSG_DEBUG(" [+] Next dense volume found: '"
1635 << cache.m_currentDense->volumeName() << "'.");
1636 break;
1637 }
1638 } // loop over dense volumes
1639 }
1640 } else {
1641 cache.m_currentDense = nextVol;
1642 ATH_MSG_DEBUG(" [+] Next dense volume: '" << cache.m_currentDense->volumeName()
1643 << "'.");
1644 }
1645 }
1646 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() +
1647 cache.m_layers.size() + cache.m_denseBoundaries.size() +
1648 cache.m_navigBoundaries.size()) {
1649 // navig volume boundary
1650 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() -
1651 cache.m_layers.size() - cache.m_denseBoundaries.size();
1652 std::vector<std::pair<const Trk::TrackingVolume*, unsigned int>>::iterator nIter =
1653 cache.m_navigVolsInt.begin();
1654 while (nIter != cache.m_navigVolsInt.end() && index >= (*nIter).second) {
1655 index -= (*nIter).second;
1656 ++nIter;
1657 }
1658 if (nIter != cache.m_navigVolsInt.end()) {
1659 currVol = (*nIter).first;
1660 nextVol =
1661 ((*nIter).first->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
1662 // boundary orientation not reliable
1663 const Amg::Vector3D tp =
1664 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
1665 if (nextVol && nextVol->inside(tp, 0.)) {
1666 ATH_MSG_DEBUG(" [+] Navigation volume boundary, entering volume '"
1667 << nextVol->volumeName() << "'.");
1668 } else if (currVol->inside(tp, 0.)) {
1669 nextVol = currVol;
1670 ATH_MSG_DEBUG(" [+] Navigation volume boundary, entering volume '"
1671 << nextVol->volumeName() << "'.");
1672 } else {
1673 nextVol = nullptr;
1674 ATH_MSG_DEBUG(" [+] Navigation volume boundary, leaving volume '"
1675 << currVol->volumeName() << "'.");
1676 }
1677 // not necessary: currPar = nextPar; since done outside the loop and currPar not used
1678 // inside the loop return only if detached volume boundaries not collected
1679 if (nextVol) {
1681 ctx, cache, prop, nextPar, destSurf, cache.m_currentStatic,
1682 dir, bcheck, particle, matupmode);
1683 }
1684 }
1685 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() +
1686 cache.m_layers.size() + cache.m_denseBoundaries.size() +
1687 cache.m_navigBoundaries.size() +
1688 cache.m_detachedBoundaries.size()) {
1689 // detached volume boundary
1690 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() -
1691 cache.m_layers.size() - cache.m_denseBoundaries.size() -
1692 cache.m_navigBoundaries.size();
1693 std::vector<std::pair<const Trk::DetachedTrackingVolume*, unsigned int>>::iterator dIter =
1694 cache.m_detachedVols.begin();
1695 while (dIter != cache.m_detachedVols.end() && index >= (*dIter).second) {
1696 index -= (*dIter).second;
1697 ++dIter;
1698 }
1699 if (dIter != cache.m_detachedVols.end()) {
1700 currVol = (*dIter).first->trackingVolume();
1701 // boundary orientation not reliable
1702 nextVol =
1703 ((*dIter).first->trackingVolume()->boundarySurfaces())[index]->attachedVolume(
1704 *nextPar, dir);
1705 const Amg::Vector3D tp =
1706 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
1707 if (nextVol && nextVol->inside(tp, 0.)) {
1708 ATH_MSG_DEBUG(" [+] Detached volume boundary, entering volume '"
1709 << nextVol->volumeName() << "'.");
1710 } else if (currVol->inside(tp, 0.)) {
1711 nextVol = currVol;
1712 ATH_MSG_DEBUG(" [+] Detached volume boundary, entering volume '"
1713 << nextVol->volumeName() << "'.");
1714 } else {
1715 nextVol = nullptr;
1716 ATH_MSG_DEBUG(" [+] Detached volume boundary, leaving volume '"
1717 << currVol->volumeName() << "'.");
1718 }
1719 // not necessary: currPar = nextPar; since done outside the loop and currPar not used
1720 // inside the loop if ( nextVol || !detachedBoundariesIncluded)
1721 if (nextVol) {
1723 ctx, cache, prop, nextPar, destSurf, cache.m_currentStatic,
1724 dir, bcheck, particle, matupmode);
1725 }
1726 }
1727 }
1728 iSol++;
1729 }
1730 } else {
1731 ATH_MSG_DEBUG(" [!] Propagation failed, return 0");
1732 cache.m_parametersAtBoundary.boundaryInformation(cache.m_currentStatic, nextPar, nextPar);
1733 return {};
1734 }
1735 currPar = nextPar;
1736 }
1737
1738 return {};
1739}
1740
1743 Cache& cache,
1744 const IPropagator& prop,
1746 const Trk::Surface* destSurf,
1748 PropDirection dir,
1749 ParticleHypothesis particle) const
1750{
1751 ++cache.m_methodSequence;
1752 ATH_MSG_DEBUG("M-[" << cache.m_methodSequence << "] extrapolateInAlignableTV(...) ");
1753
1754 // material loop in sensitive Calo volumes
1755 // extrapolation without target surface returns:
1756 // A) boundary parameters (static volume boundary)
1757 // if target surface:
1758 // B) trPar at target surface
1759 // material collection done by the propagator ( binned material used )
1760
1761 // initialize the return parameters vector
1763 const Trk::AlignableTrackingVolume* staticVol = nullptr;
1764 const Trk::TrackingVolume* currVol = nullptr;
1765 const Trk::TrackingVolume* nextVol = nullptr;
1766 std::vector<unsigned int> solutions;
1767 const Trk::TrackingVolume* assocVol = nullptr;
1768 // double tol = 0.001;
1769 // double path = 0.;
1770 // set tracking geometry in cache
1771 cache.setTrackingGeometry(*m_navigator,ctx);
1772 if (!cache.m_highestVolume) {
1773 cache.m_highestVolume = m_navigator->highestVolume(ctx);
1774 }
1775
1776 // verify current position
1777 const Amg::Vector3D gp = parm->position();
1778 if (vol && vol->inside(gp, m_tolerance)) {
1779 staticVol = vol;
1780 } else {
1782 const Trk::TrackingVolume* nextStatVol = nullptr;
1783 if (m_navigator->atVolumeBoundary(currPar, currVol, dir, nextStatVol, m_tolerance) &&
1784 nextStatVol != currVol) {
1785 currVol = nextStatVol;
1786 }
1787 if (currVol && currVol != vol) {
1788 if (currVol->isAlignable()) {
1789 const Trk::AlignableTrackingVolume* aliTG =
1790 static_cast<const Trk::AlignableTrackingVolume*>(currVol);
1791 staticVol = aliTG;
1792 }
1793 }
1794 }
1795
1796 if (!staticVol) {
1797 ATH_MSG_DEBUG(" [!] failing in retrieval of AlignableTV, return 0");
1798 return {};
1799 }
1800
1801 // save volume entry if collection present
1802 if (cache.m_identifiedParameters) {
1803 const Trk::BinnedMaterial* binMat = staticVol->binnedMaterial();
1804 if (binMat) {
1805 const Trk::IdentifiedMaterial* binIDMat = binMat->material(currPar->position());
1806 if (binIDMat->second > 0) {
1807 std::unique_ptr<Trk::TrackParameters> identified_parm = currPar->uniqueClone();
1808 cache.m_identifiedParameters->push_back(
1809 std::pair<std::unique_ptr<Trk::TrackParameters>, int>(std::move(identified_parm), binIDMat->second));
1810 }
1811 }
1812 }
1813
1814 // navigation surfaces
1815 if (cache.m_navigSurfs.capacity() > m_maxNavigSurf) {
1816 cache.m_navigSurfs.reserve(m_maxNavigSurf);
1817 }
1818 cache.m_navigSurfs.clear();
1819
1820 if (destSurf) {
1821 cache.m_navigSurfs.emplace_back(destSurf, false);
1822 }
1823
1824 // assume new static volume, retrieve boundaries
1825 cache.m_currentStatic = staticVol;
1826 cache.retrieveBoundaries();
1827
1828 cache.m_navigSurfs.insert(
1829 cache.m_navigSurfs.end(), cache.m_staticBoundaries.begin(), cache.m_staticBoundaries.end());
1830
1831 // current dense
1832 cache.m_currentDense = staticVol;
1833
1834 // ready to propagate
1835 // till: A/ static volume boundary(bcheck=true) , B/ destination surface(bcheck=false)
1836
1837 nextVol = nullptr;
1838 while (currPar) {
1839 double path = 0.;
1840 std::vector<unsigned int> solutions;
1841 // propagate now
1842 ATH_MSG_DEBUG(" [+] Starting propagation at position "
1843 << positionOutput(currPar->position())
1844 << " (current momentum: " << currPar->momentum().mag() << ")");
1845 ATH_MSG_DEBUG(" [+] " << cache.m_navigSurfs.size() << " target surfaces in '"
1846 << cache.m_currentDense->volumeName() << "'.");
1847 // arguments : inputParameters, vector of navigation surfaces, propagation direction, b field
1848 // service, particle
1849 // type, result,
1850 // material collection, intersection collection, path limit, switch for use of path limit,
1851 // switch for curvilinear on return, current TG volume
1852 if (m_dumpCache && cache.m_extrapolationCache) {
1853 ATH_MSG_DEBUG(" prop.propagateM " << cache.m_extrapolationCache);
1854 }
1855 identifiedParameters_t* intersections = cache.m_identifiedParameters.get();
1857 ctx, *currPar, cache.m_navigSurfs, dir, m_fieldProperties, particle,
1858 solutions, cache.m_matstates, intersections, path, false, false,
1859 cache.m_currentDense, cache.m_extrapolationCache));
1860
1861 if (nextPar) {
1862 ++cache.m_nPropagations;
1863 ATH_MSG_DEBUG(" [+] Position after propagation - at "
1864 << positionOutput(nextPar->position()));
1865 ATH_MSG_DEBUG(" [+] Number of intersection solutions: " << solutions.size());
1866 // destination surface
1867 if (destSurf && solutions[0] == 0) {
1868 return nextPar;
1869 }
1870 if (destSurf && solutions.size() > 1 && solutions[1] == 0) {
1871 return nextPar;
1872 }
1873 // destination surface missed ?
1874 if (destSurf) {
1875 double dist = 0.;
1876 const Trk::DistanceSolution distSol = destSurf->straightLineDistanceEstimate(
1877 nextPar->position(), nextPar->momentum().normalized());
1878 if (distSol.numberOfSolutions() > 0) {
1879 dist = distSol.first();
1880 if (distSol.numberOfSolutions() > 1 && std::abs(dist) < m_tolerance) {
1881 dist = distSol.second();
1882 }
1883 if (distSol.numberOfSolutions() > 1 && dist * dir < 0. && distSol.second() * dir > 0.) {
1884 dist = distSol.second();
1885 }
1886 } else {
1887 dist = distSol.toPointOfClosestApproach();
1888 }
1889 if (dist * dir < 0.) {
1890 ATH_MSG_DEBUG(" [+] Destination surface missed ? " << dist << "," << dir);
1892 return {};
1893 }
1894 ATH_MSG_DEBUG(" [+] New 3D-distance to destinatiion - d3 = " << dist * dir);
1895 }
1896
1897 int const iDest = destSurf ? 1 : 0;
1898 unsigned int iSol = 0;
1899 while (iSol < solutions.size()) {
1900 if (solutions[iSol] < iDest + cache.m_staticBoundaries.size()) {
1901 // TODO if massive boundary coded, add the material effects here
1902 // static volume boundary; return to the main loop : TODO move from misaligned to static
1903 const unsigned int index = solutions[iSol] - iDest;
1904 // use global coordinates to retrieve attached volume (just for static!)
1905 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
1906 nextPar->position(), nextPar->momentum(), dir);
1907 // double check the next volume
1908 if (nextVol &&
1909 !(nextVol->inside(nextPar->position() + 0.01 * dir * nextPar->momentum().normalized(),
1910 m_tolerance))) {
1911 ATH_MSG_DEBUG(" [!] WARNING: wrongly assigned static volume ?"
1912 << cache.m_currentStatic->volumeName() << "->" << nextVol->volumeName());
1914 nextPar->position() + 0.01 * nextPar->momentum().normalized());
1915 if (nextVol) {
1916 ATH_MSG_DEBUG(" new search yields: " << nextVol->volumeName());
1917 }
1918 }
1919 // end double check - to be removed after validation of the geometry gluing
1920 // lateral exit from calo sample can be handled here
1921 if (cache.m_identifiedParameters) {
1922 const Trk::BinnedMaterial* binMat = staticVol->binnedMaterial();
1923 if (binMat) {
1924 const Trk::IdentifiedMaterial* binIDMat = binMat->material(nextPar->position());
1925 // save only if entry to the sample present, the exit missing and non-zero step in the
1926 // sample
1927 if (binIDMat && binIDMat->second > 0 && !cache.m_identifiedParameters->empty() &&
1928 cache.m_identifiedParameters->back().second == binIDMat->second) {
1929 const double s =
1930 (nextPar->position() - cache.m_identifiedParameters->back().first->position())
1931 .mag();
1932 if (s > 0.001) {
1933 std::unique_ptr<Trk::TrackParameters> identified_parm = nextPar->uniqueClone();
1934 cache.m_identifiedParameters->push_back(
1935 std::pair<std::unique_ptr<Trk::TrackParameters>, int>(std::move(identified_parm),
1936 -binIDMat->second));
1937 }
1938 }
1939 }
1940 }
1941 // end lateral exit handling
1942 if (nextVol != cache.m_currentStatic) {
1943 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
1944 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '"
1945 << cache.m_currentStatic->volumeName() << "'.");
1946 if (m_navigator->atVolumeBoundary(
1947 nextPar, cache.m_currentStatic, dir, assocVol, m_tolerance) &&
1948 assocVol != cache.m_currentStatic) {
1949 cache.m_currentDense = m_useMuonMatApprox ? nextVol : cache.m_highestVolume;
1950 }
1951 // no next volume found --- end of the world
1952 if (!nextVol) {
1953 ATH_MSG_DEBUG(" [+] Word boundary reached - at "
1954 << positionOutput(nextPar->position()));
1955 }
1956 // next volume found and parameters are at boundary
1957 if (nextVol && nextPar) {
1958 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
1959 ATH_MSG_DEBUG(" [+] Crossing position is - at "
1960 << positionOutput(nextPar->position()));
1961 if (!destSurf) {
1962 return nextPar; // return value differs between e->surface (cached boundary values
1963 // used)
1964 }
1965 // implicit : parameters at boundary returned
1966 }
1967 return {};
1968 }
1969 }
1970 iSol++;
1971 }
1972 } else {
1973 ATH_MSG_DEBUG(" [!] Propagation failed, return 0");
1974 cache.m_parametersAtBoundary.boundaryInformation(cache.m_currentStatic, nextPar, nextPar);
1975 return {};
1976 }
1977 currPar = nextPar;
1978 }
1979
1980 return {};
1981}
1982
1983std::unique_ptr<Trk::TrackParameters>
1985 const IPropagator& prop,
1986 const Trk::TrackParameters& parm,
1987 const Trk::Surface& sf,
1989 const Trk::BoundaryCheck& bcheck,
1990 Trk::ParticleHypothesis particle) const
1991{
1992 // statistics && sequence output ----------------------------------------
1994 return prop.propagate(ctx, parm, sf, dir, bcheck, m_fieldProperties, particle);
1995}
1996
1997std::unique_ptr<Trk::TrackParameters>
1999 const IPropagator& prop,
2000 const TrackParameters& parm,
2001 const TrackingVolume& vol,
2002 PropDirection dir,
2003 ParticleHypothesis particle) const
2004{
2005 // @TODO in principle the cache should already be created
2006 // here to correctly set cache.m_methodSequence for sub-sequent calls ...
2007 ATH_MSG_DEBUG("V-[?" /*<< cache.m_methodSequence*/
2008 << "] extrapolateToVolume(...) to volume '" << vol.volumeName() << "'.");
2009 std::unique_ptr<TrackParameters> returnParms = nullptr;
2010 Trk::PropDirection const propDir = dir == Trk::oppositeMomentum ? dir : Trk::alongMomentum;
2011 double dist = 0.;
2012
2013 // retrieve boundary surfaces, order them according to distance estimate
2014 const auto& bounds = vol.boundarySurfaces();
2015 std::vector<std::pair<const Trk::Surface*, double>> surfaces;
2016 surfaces.reserve(bounds.size());
2017 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
2018 const Trk::Surface* nextSurface = &((bounds[ib])->surfaceRepresentation());
2019 if (nextSurface) {
2020 const Trk::DistanceSolution distSol = nextSurface->straightLineDistanceEstimate(
2021 parm.position(), propDir * parm.momentum().normalized());
2022 if (distSol.numberOfSolutions() > 0) {
2023 dist = distSol.first();
2024 } else {
2025 dist = distSol.toPointOfClosestApproach();
2026 }
2027 if (!surfaces.empty() && distSol.numberOfSolutions() >= 0 && dist < surfaces.back().second) {
2028 std::vector<std::pair<const Trk::Surface*, double>>::iterator sIter = surfaces.begin();
2029 while (sIter != surfaces.end()) {
2030 if (dist < (*sIter).second) {
2031 break;
2032 }
2033 ++sIter;
2034 }
2035 sIter = surfaces.insert(sIter, (std::pair<const Trk::Surface*, double>(nextSurface, dist)));
2036 } else {
2037 surfaces.emplace_back(nextSurface, dist);
2038 }
2039 }
2040 }
2041
2042 // solution along path
2043 for (std::pair<const Trk::Surface*, double> const& a_surface : surfaces) {
2044 if (a_surface.second > 0) {
2045 Cache cache(m_propStat);
2047 // Material effect updator cache
2049 returnParms = cache.m_ownedPtrs.move(
2050 extrapolateImpl(ctx, cache, prop, cloneInput, *(a_surface.first),
2051 propDir, true, particle));
2052 if (returnParms.get() == &parm) {
2053 throw std::logic_error("Did not create new track parameters.");
2054 }
2055 if (returnParms) {
2056 break;
2057 }
2058 }
2059 }
2060
2061 if (!returnParms && dir == anyDirection) {
2062 for (std::vector<std::pair<const Trk::Surface*, double>>::reverse_iterator rsIter =
2063 surfaces.rbegin();
2064 rsIter != surfaces.rend();
2065 ++rsIter) {
2066 if ((*rsIter).second < 0) {
2067 Cache cache(m_propStat);
2069 // Material effect updator cache
2071 returnParms = cache.m_ownedPtrs.move(
2072 extrapolateImpl(ctx, cache, prop, cloneInput, *((*rsIter).first),
2073 Trk::oppositeMomentum, true, particle));
2074 if (returnParms.get() == &parm) {
2075 throw std::logic_error("Did not create new track parameters.");
2076 }
2077
2078 if (returnParms) {
2079 break;
2080 }
2081 }
2082 }
2083 }
2084 // cache.m_methodSequence=0; // originially m_methodSequence was reset here but cache not
2085 // available here
2086 return returnParms;
2087}
2088
2091 Cache& cache,
2092 const IPropagator& prop,
2094 const Trk::Surface& sf,
2096 const Trk::BoundaryCheck& bcheck,
2097 Trk::ParticleHypothesis particle,
2098 MaterialUpdateMode matupmode) const
2099{
2100
2101 // reset the destination surface
2102 cache.m_destinationSurface = nullptr;
2103 cache.m_lastValidParameters = nullptr;
2104 // skip rest of navigation if particle hypothesis is nonInteracting
2105 if (particle == Trk::nonInteracting) {
2106 if (cache.m_methodSequence) {
2107 ++cache.m_methodSequence; // extrapolateDirectly does not have the cache and cannot increment
2108 // m_methodSequence therefore do it here
2109 }
2110 return cache.m_ownedPtrs.push(extrapolateDirectlyImpl(ctx, prop, *parm, sf, dir, bcheck, particle));
2111 }
2112
2113 // set the model action of the material effects updaters
2114 for (unsigned int imueot = 0; imueot < m_subupdaters.size(); ++imueot) {
2115 if(m_subupdaters[imueot]){
2116 m_subupdaters[imueot]->modelAction((cache.m_MaterialUpCache[imueot]));
2117 }
2118 }
2119
2120 // statistics && sequence output ----------------------------------------
2122 ++cache.m_methodSequence;
2123 // prepare the values for the startup and call the initialization
2124 // ------------------------------------------
2125 const Trk::TrackingVolume* startVolume = nullptr;
2126 const Trk::TrackingVolume* destVolume = nullptr;
2127 const Trk::Layer* nextLayer = nullptr;
2128 const Trk::TrackingVolume* nextVolume = nullptr;
2129 const Trk::TrackingVolume* lastVolume = nullptr;
2130 Trk::TrackParameters* refParameters = nullptr;
2131 Trk::TrackParameters* lastParameters = nullptr;
2132 Trk::TrackParameters* navParameters = nullptr;
2133 Trk::CacheOwnedPtr<Trk::TrackParameters> nextParameters = parm;
2134 // initialize Navigation (calls as well initialize on garbe collection)
2135 // -------------------------------------
2136 Trk::PropDirection const navDir =
2137 initializeNavigation(ctx, cache, prop, nextParameters, sf, dir, particle,
2138 refParameters, nextLayer, nextVolume, destVolume);
2139 // ----------------------------
2140 // if anyDirection has been chosen as a start directive:
2141 // -> overwrite the dir with the navigation direction
2142 dir = (dir == Trk::anyDirection) ? navDir : dir;
2143 // check for consistency
2144 if (dir == Trk::anyDirection || navDir != dir) {
2145 // navigation could not be resolved
2147 " [!] Navigation direction could not be resolved, switching to extrapolateDirectly()");
2148 // the extrapolate directly call
2149 ++cache.m_methodSequence; // extrapolateDirectly does not have the cache and cannot increment
2150 // m_methodSequence
2151 return cache.m_ownedPtrs.push(extrapolateDirectlyImpl(ctx, prop, *parm, sf, navDir, bcheck, particle));
2152 }
2153 // ------------------------------
2154 startVolume = nextVolume;
2155 // fallback setup -------------------------------------
2156 bool fallback = false;
2157 // ------- initial distance estimation ---------------
2158 double currentDistance = 0.;
2159 double previousDistance = 0.;
2160 // reference parameters and distance solution: use consistently one of each
2161 if (refParameters) {
2162 ATH_MSG_VERBOSE(" [+] Reference Parameters - at "
2163 << positionOutput(refParameters->position()));
2164 currentDistance = (refParameters->position() - parm->position()).mag();
2165 } else {
2166 // using fast but accureate sl distance from surface
2167 const Trk::DistanceSolution distSol =
2168 sf.straightLineDistanceEstimate(parm->position(), dir * parm->momentum().normalized());
2169 if (distSol.numberOfSolutions() > 0) {
2170 currentDistance = distSol.absClosest();
2171 } else {
2172 currentDistance = std::abs(distSol.toPointOfClosestApproach());
2173 }
2174 // VERBOSE output
2175 }
2176 ATH_MSG_VERBOSE(" [+] Initial 3D-distance to destination - d3 = " << currentDistance);
2177 // and for oscillation protection ----------------------------------------------------
2178 const Trk::TrackingVolume* previousVolume = nullptr;
2179 // -----------------------------------------------------------------------------------
2180
2182 " [" << cache.m_methodSequence << "] extrapolate() "
2183 << ((nextVolume) ? nextVolume->volumeName() : "Unknown (ERROR)")
2184 << " -> "
2185 << (destVolume ? destVolume->volumeName()
2186 : "Unknown (blind extrapolation)"));
2187 ATH_MSG_VERBOSE(" [+] Starting position determined - at "
2188 << positionOutput(parm->position()));
2189 if (nextLayer) {
2190 ATH_MSG_VERBOSE(" [+] Starting layer determined - with " << layerRZoutput(*nextLayer));
2191 }
2192
2193 // -----------------------------------------------------------------------------------
2194 const IPropagator* currentPropagator = nullptr;
2195 // ----------------- extrapolation from One Volume to the next Volume
2196 // -------------------------------------- the loop continues while:
2197 // - nextVolume extists
2198 // - nextVolume is different from lastVolume (prevent infinite loops)
2199 // - nextVolume is different from destinationVolume (change to extrapolateInsideVolume)
2200 // - nextParameters exist
2201 // - lastVolume is different from previousVolume (prevent oscillation loop,
2202 // one-time-punch-through allowed)
2203 // - the reinforced navigation can find destination parameters
2204 // - the maximum method sequence is not met
2205
2206 // best starting parameters
2207 bool updateLastValid = true;
2208 // one-time-punch-through allows for volume2 - volume1 - volume2 (cosmics)
2209 bool punchThroughDone = false;
2210
2211 auto navigationBreakOscillation = m_navigationBreakOscillation.buffer();
2212 auto navigationBreakNoVolume = m_navigationBreakNoVolume.buffer();
2213 auto navigationBreakDistIncrease = m_navigationBreakDistIncrease.buffer();
2214 auto navigationBreakVolumeSignature = m_navigationBreakVolumeSignature.buffer();
2215
2216 while (nextVolume && nextVolume != destVolume && nextVolume != lastVolume && nextParameters &&
2218 // chose the propagtor type
2219 currentPropagator = subPropagator(*nextVolume);
2220 if (!currentPropagator) {
2221 // [0] Navigation break : configuration problem or consistency problem of TrackingGeometry
2222 // output
2223 ATH_MSG_DEBUG(" [X] Navigation break [X]");
2224 ATH_MSG_DEBUG(" - Reason : No Propagator found for Volume '"
2225 << nextVolume->volumeName() << "'");
2226 // debug statistics
2228 // trigger the fallback solution
2229 fallback = true;
2230 break;
2231 }
2232
2233 // check for the distance to destination
2234 // -------------------------------------------------------------
2235 if (updateLastValid) {
2236 cache.m_lastValidParameters = nextParameters;
2237 }
2238 // avoid the oszillation
2239 previousVolume = lastVolume;
2240 // for the next step to termine if infinite loop occurs
2241 lastVolume = nextVolume;
2242 // for memory cleanup and backup
2243 lastParameters = nextParameters;
2244
2245 // MS specific code ------------------
2246 // extrapolation within detached volumes - returns parameters on destination surfaces, or
2247 // boundary solution handles also dense volume description in Calo and beam pipe
2248 if (nextVolume->geometrySignature() > 1) {
2252 // extrapolate to volume boundary to avoid navigation break
2254 cache.m_ownedPtrs.push(currentPropagator->propagate(
2257 dir, bcheck,
2258 // *previousVolume,
2259 m_fieldProperties, particle, false, previousVolume));
2260 // set boundary and next parameters
2261 cache.m_parametersAtBoundary.boundaryInformation(nextVolume, nextPar, nextPar);
2262 nextParameters = cache.m_parametersAtBoundary.nextParameters;
2263 navParameters = cache.m_parametersAtBoundary.navParameters;
2264 }
2265 // start from the nextParameter (which are at volume boundary)
2266 Trk::CacheOwnedPtr<Trk::TrackParameters> resultParameters = nullptr;
2267 if (nextParameters) {
2268 if (!m_stepPropagator) {
2270 "extrapolation in Calo/MS called without configured STEP propagator, aborting");
2271 return {};
2272 }
2273 resultParameters = extrapolateWithinDetachedVolumes(
2274 ctx, cache, *m_stepPropagator, nextParameters, sf,
2275 *nextVolume, dir, bcheck, particle, matupmode);
2276 }
2277 if (resultParameters) {
2278 // destination reached : indicated through result parameters
2279 // set the model action of the material effects updaters
2280 for (unsigned int imueot = 0; imueot < m_subupdaters.size(); ++imueot) {
2281 if(m_subupdaters[imueot]){
2282 m_subupdaters[imueot]->modelAction((cache.m_MaterialUpCache[imueot]));
2283 }
2284 }
2285 // return the parameters at destination
2286 ATH_MSG_DEBUG(" [+] Destination surface successfully hit.");
2287 // return the result (succesful)
2288 return resultParameters;
2291 cache.m_status != Cache::kContinue) {
2292 ATH_MSG_DEBUG(" [-] Destination surface could not be hit.");
2293 return resultParameters;
2294 }
2295 } else {
2296 // -------------------------------------------------------------------------
2297 // standard loop over volumes (but last one)
2298 // extrapolate to volume boundary - void method as 'cache.m_parametersAtBoundary' hold the
2299 // information
2301 cache,
2302 *currentPropagator,
2303 nextParameters,
2304 nextLayer,
2305 *nextVolume,
2306 dir,
2307 bcheck,
2308 particle,
2309 matupmode);
2310 }
2311 // go on with the next volume / get next Volume and Boundary from the private member
2312 nextVolume = cache.m_parametersAtBoundary.nextVolume;
2313 nextParameters = cache.m_parametersAtBoundary.nextParameters;
2314 navParameters = cache.m_parametersAtBoundary.navParameters;
2315 // new distance estimation ( after step to next volume ) -------------------------
2316 previousDistance = currentDistance;
2317 // make it either from the navParmaters (if the exist) or the nextParameters
2318 {
2319 const Trk::TrackParameters* distParameters =
2322 : nextParameters;
2323
2324 if (distParameters) {
2325 // use consistently either the:
2326 // (A) reference parameters or the
2327 if (refParameters) {
2328 currentDistance = (refParameters->position() - distParameters->position()).mag();
2329 } else {
2330 // (B) distance solution to surface
2331 const Trk::DistanceSolution newDistSol = sf.straightLineDistanceEstimate(
2332 distParameters->position(), dir * distParameters->momentum().normalized());
2333 currentDistance = newDistSol.numberOfSolutions() > 0
2334 ? newDistSol.absClosest()
2335 : std::abs(newDistSol.toPointOfClosestApproach());
2336 }
2337 }
2338 }
2339 ATH_MSG_VERBOSE(" [+] New 3D-distance to destination - d3 = "
2340 << currentDistance << " (from "
2342 ? "boundary parameters"
2343 : "last parameters within volume ")
2344 << ")");
2345
2346 // --------------------------------------------------------------------------------
2347 // (1) NAVIGATION BREAK : next Volume is identical to last volume -- LOOP
2348 if (nextVolume == lastVolume && nextVolume) {
2349 // ST false when crossing beam pipe : additional check on step distance
2350 if (nextParameters && lastParameters &&
2351 (nextParameters->position() - lastParameters->position())
2352 .dot(lastParameters->momentum().normalized()) *
2353 dir >
2354 0.001) {
2355 } else {
2356 // output
2357 ATH_MSG_DEBUG(" [X] Navigation break [X]");
2358 if (nextParameters && lastParameters) {
2360 "last step:" << (nextParameters->position() - lastParameters->position()).mag());
2361 }
2362 ATH_MSG_DEBUG("- Reason : Loop detected in TrackingVolume '"
2363 << nextVolume->volumeName() << "'");
2364 // statistics
2366 // fallback flag
2367 fallback = true;
2368 // break it
2369 break;
2370 }
2371 }
2372 // (2) NAVIGATION BREAK : Oscillation
2373 else if (nextVolume == previousVolume && nextVolume) {
2374 // one time the loop oscillation has been allowed already
2375 if (punchThroughDone) {
2376 // output
2377 ATH_MSG_DEBUG(" [X] Navigation break [X]");
2378 ATH_MSG_DEBUG("- Reason : Oscillation detected in TrackingVolume '"
2379 << nextVolume->volumeName() << "'");
2380 // statistics
2381 ++navigationBreakOscillation;
2382 // fallback flag
2383 fallback = true;
2384 // break it
2385 break;
2386 }
2387 // set the punch-through to true
2388 punchThroughDone = true;
2389 ATH_MSG_DEBUG(" [!] One time punch-through a volume done.");
2390
2391 }
2392 // ------------------- the output interpretationn of the extrapolateToVolumeBoundary
2393 // (3) NAVIGATION BREAK : no nextVolume found - but not in extrapolateBlindly() mode
2394 else if (!nextVolume && !cache.m_parametersOnDetElements && lastVolume &&
2396 // output
2397 ATH_MSG_VERBOSE(" [X] Navigation break [X]");
2398 ATH_MSG_VERBOSE("- Reason : No next volume found of TrackingVolume '"
2399 << lastVolume->volumeName() << "'");
2400 // statistics
2401 ++navigationBreakNoVolume;
2402 // record the "no next" volume -- increase the counter for the (last) volume
2403 // fallback flag
2404 fallback = true;
2405 // break it
2406 break;
2407 }
2408 // ------------------- the output interpretationn of the extrapolateToVolumeBoundary
2409 // (4) NAVIGATION BREAK : // nextParameters found but distance to surface increases
2410 else if (nextParameters && !cache.m_parametersOnDetElements && navParameters && nextVolume &&
2411 currentDistance > s_distIncreaseTolerance + previousDistance) {
2412 // output
2413 ATH_MSG_DEBUG(" [X] Navigation break [X]");
2414 ATH_MSG_DEBUG(" - Reason : Distance increase [ "
2415 << previousDistance << " to " << currentDistance << "] in TrackingVolume '"
2416 << nextVolume->volumeName() << "'");
2417 // statistics
2418 ++navigationBreakDistIncrease;
2419 // record the "dist increase" volume -- increase the counter for the volume
2420 // fallback flag
2421 fallback = true;
2422 break;
2423 }
2424 // ------------------- the output interpretationn of the extrapolateToVolumeBoundary
2425 // (+) update killed track
2426 else if ((!nextParameters && m_stopWithUpdateZero) || !nextVolume) {
2427 ATH_MSG_DEBUG(" [+] Navigation stop : either the update killed the "
2428 "track, or end of detector/boundary volume reached");
2429 return {};
2430 }
2431 // ------------------- the output interpretationn of the extrapolateToVolumeBoundary
2432 // (+) end of extrapolate blindly(volume*)
2433 else if (cache.m_boundaryVolume && navParameters &&
2434 !(cache.m_boundaryVolume->inside(navParameters->position()))) {
2436 " [+] Navigation stop : next navigation step would lead outside given boundary volume");
2437 return {};
2438 }
2439 // ------------------- the output interpretationn of the extrapolateToVolumeBoundary
2440 // (5) NAVIGATION BREAK : // nextParameters found but distance to surface increases
2441 else if (nextVolume) {
2442 ATH_MSG_DEBUG(" [+] next Tracking Volume = " << nextVolume->volumeName());
2443 }
2444 // set validity of last parameters to cache ------------------------------------------
2445 updateLastValid = !nextParameters || cache.m_parametersOnDetElements || !navParameters ||
2446 !nextVolume || currentDistance <= previousDistance;
2447 // reset
2448 if (!nextParameters) {
2449 nextParameters = lastParameters;
2450 }
2451 // one volume step invalidates the nextLayer information
2452 nextLayer = nullptr;
2453 }
2454
2455 // ------------------- fallback was triggered in volume to volume loop
2456 // --------------------------------------
2457 if (fallback) {
2458 // continue with the output
2459 ATH_MSG_DEBUG(" - Consequence : " << (m_stopWithNavigationBreak
2460 ? "return 0 (configured) "
2461 : "switch to extrapolateDirectly() "));
2462 // stop with navigaiton break or zero update
2464 return {};
2465 }
2466 if (cache.m_lastValidParameters && lastVolume) {
2467 currentPropagator = subPropagator(*lastVolume);
2468 }
2469 if (!currentPropagator) {
2470 return {};
2471 }
2472 // create the result now
2474 cache.m_ownedPtrs.push(currentPropagator->propagate(
2475 ctx, *cache.m_lastValidParameters, sf, Trk::anyDirection, bcheck,
2476 m_fieldProperties, particle, false, lastVolume));
2477 // desperate try
2478 if (!resultParameters) {
2479 resultParameters = cache.m_ownedPtrs.push(currentPropagator->propagate(
2480 ctx, *parm, sf, dir, bcheck, m_fieldProperties, particle, false,
2481 startVolume));
2482 }
2483 return resultParameters;
2484 }
2485
2486 // ----------------- this is the exit of the extrapolateBlindly() call
2487 // --------------------------------------
2488 if ((&sf) == (m_referenceSurface.get())) {
2489 return {};
2490 }
2491
2492 // ---------------- extrapolation inside the Volume -----------------------------------
2493 // Trk::CacheOwnedPtr<Trk::TrackParameters> finalNextParameters(cache.trackParmContainer(),nextParameters);
2494 Trk::CacheOwnedPtr<Trk::TrackParameters> finalNextParameters = nextParameters;
2495 ATH_MSG_DEBUG("create finalNextParameters " << *finalNextParameters);
2496 Trk::CacheOwnedPtr<Trk::TrackParameters> resultParameters = nullptr;
2497 if (nextVolume) {
2498 // chose the propagator fromt he geometry signature
2499 currentPropagator = subPropagator(*nextVolume);
2500 // extrapolate inside the volume
2501 if (currentPropagator) {
2502 resultParameters = extrapolateInsideVolume(
2503 ctx, cache, *currentPropagator, nextParameters, sf, nextLayer,
2504 *nextVolume, dir, bcheck, particle, matupmode);
2505 }
2506 }
2507 // -------------------------------------------------------------------------------------
2508 // the final - desperate backup --- just try to hit the surface
2509 if (!resultParameters && !m_stopWithNavigationBreak && !m_stopWithUpdateZero) {
2510 if (finalNextParameters)
2511 ATH_MSG_DEBUG("propagate using parameters " << *finalNextParameters);
2512 else {
2513 ATH_MSG_DEBUG("no finalNextParameters, bailing out of extrapolateDirectly");
2514 return {};
2515 }
2516 ATH_MSG_DEBUG(" [-] Fallback to extrapolateDirectly triggered ! ");
2517 resultParameters = cache.m_ownedPtrs.push(
2518 prop.propagate(ctx, *finalNextParameters, sf, dir, bcheck,
2519 // *startVolume,
2520 m_fieldProperties, particle, false, startVolume));
2521 }
2522 // return whatever you have
2523 return resultParameters;
2524}
2525
2528 Cache& cache,
2529 const IPropagator& prop,
2531 const std::vector<MaterialEffectsOnTrack>& sfMeff,
2532 const TrackingVolume& tvol,
2533 PropDirection dir,
2534 ParticleHypothesis particle,
2535 MaterialUpdateMode matupmode) const
2536{
2537 // statistics && sequence output ----------------------------------------
2538 if (cache.m_methodSequence) {
2539 ++cache.m_methodSequence;
2540 }
2541 ATH_MSG_DEBUG("D-[" << cache.m_methodSequence
2542 << "] extrapolate with given MaterialEffectsOnTrack in Volume '"
2543 << tvol.volumeName() << "'.");
2544
2546
2547 // loop over the provided material effects on track
2548 for (const MaterialEffectsOnTrack& a_sfMeff : sfMeff) {
2549 // first propagate to the given surface
2550 // nextParameters = prop.propagate(*nextParameters, sfMeffI->associatedSurface(),dir,true,tvol,
2551 // particle);
2553 prop.propagate(ctx, *currPar, a_sfMeff.associatedSurface(), dir, true,
2554 m_fieldProperties, particle, false, &tvol));
2555 // user might have not calculated well which surfaces are intersected ...
2556 // break if break
2557 if (!nextPar) {
2558 // only return track parameters if at least one iteration was successful
2559 return (currPar!= parm)
2560 ? currPar
2561 : nullptr;
2562 }
2563 currPar = nextPar;
2564 // then update
2565
2566 const IMaterialEffectsUpdator* currentUpdator = subMaterialEffectsUpdator(tvol);
2567 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
2569
2571 if (currentUpdator) {
2572 upNext = cache.m_ownedPtrs.push(currentUpdator->update(
2573 currentUpdatorCache, currPar, a_sfMeff, particle, matupmode));
2574 }
2575 if (!upNext) {
2576 // update killed the track or config problem. Return
2577 ATH_MSG_VERBOSE(" [+] Update killed track.");
2578 break;
2579 }
2580 currPar = upNext;
2581 }
2582 return currPar;
2583}
2584
2587 Cache& cache,
2589 const Surface& sf,
2590 PropDirection dir,
2591 const BoundaryCheck& bcheck,
2592 ParticleHypothesis particle,
2593 MaterialUpdateMode matupmode,
2594 Trk::ExtrapolationCache* extrapolationCache) const
2595{
2596 cache.m_extrapolationCache = extrapolationCache;
2597 cache.m_cacheEloss = extrapolationCache ? extrapolationCache->eloss() : nullptr;
2598
2599 if (extrapolationCache && m_dumpCache) {
2600 ATH_MSG_DEBUG(" In extrapolate cache pointer input: " << extrapolationCache
2601 << " cache.m_extrapolationCache "
2602 << cache.m_extrapolationCache);
2603 if (cache.m_extrapolationCache) {
2604 ATH_MSG_DEBUG(cache.to_string(" In extrapolate "));
2605 }
2606 }
2607
2608 // chose the propagator fromt he geometry signature -- start with default
2609 const IPropagator* currentPropagator =
2610 !m_subPropagators.empty() ? m_subPropagators[Trk::Global] : nullptr;
2611 if (currentPropagator) {
2612 return extrapolateImpl(ctx, cache, (*currentPropagator), parm, sf, dir,
2613 bcheck, particle, matupmode);
2614 }
2616 " [!] No default Propagator is configured ! Please check jobOptions.");
2617 return {};
2618}
2619
2622 Cache& cache,
2623 const IPropagator& prop,
2626 const Trk::BoundaryCheck& bcheck,
2627 Trk::ParticleHypothesis particle,
2628 const Trk::Volume* boundaryVol) const
2629{
2630 // statistics && sequence output ----------------------------------------
2632 ++cache.m_methodSequence;
2633 ATH_MSG_DEBUG("F-[" << cache.m_methodSequence << "] extrapolateBlindly() ");
2634 // assign the boundaryVolume
2635 cache.m_boundaryVolume = boundaryVol;
2636 // initialize the return parameters vector
2637 // create a new internal helper vector
2639 //The m_parametersOnDetElements point to it
2640 cache.m_parametersOnDetElements = &tmp;
2641 // run the extrapolation
2642 {
2643 extrapolateImpl(ctx, cache, prop, parm, *m_referenceSurface, dir, bcheck, particle);
2644 }
2645 // reset the .m_parametersOnDetElements to point to nullptr
2646 cache.m_parametersOnDetElements = nullptr;
2647 // reset the boundary Volume
2648 cache.m_boundaryVolume = nullptr;
2649 // return what you have
2650 return tmp;
2651}
2652
2653// ----------------------- The private Volume extrapolation methods --------------------------
2656 Cache& cache,
2657 const IPropagator& prop,
2659 const Surface& sf,
2660 const Layer* assocLayer,
2661 const TrackingVolume& tvol,
2662 PropDirection dir,
2663 const BoundaryCheck& bcheck,
2664 ParticleHypothesis particle,
2665 MaterialUpdateMode matupmode) const
2666{
2667 // ---> C) detached volumes exist
2668 if (!tvol.confinedDetachedVolumes().empty()) {
2670 ctx, cache, prop, parm, sf, tvol, dir, bcheck, particle, matupmode);
2671 }
2672 // ---> A) static layers exist
2674 ctx, cache, false, prop, parm, assocLayer, tvol, dir, bcheck, particle, matupmode);
2675}
2676
2679 Cache& cache,
2680 const IPropagator& prop,
2682 const Surface& sf,
2683 const TrackingVolume& tvol,
2684 PropDirection dir,
2685 const BoundaryCheck& bcheck,
2686 ParticleHypothesis particle,
2687 MaterialUpdateMode matupmode) const
2688{
2689 // method sequence output ---------------------------------
2690 ++cache.m_methodSequence;
2691 ATH_MSG_DEBUG("M-[" << cache.m_methodSequence << "] extrapolateWithinDetachedVolumes() inside '"
2692 << tvol.volumeName() << "' to destination surface. ");
2693
2694 double dist = 0.;
2695 // initialization
2696 Trk::CacheOwnedPtr<Trk::TrackParameters> nextParameters= parm;
2697 const Trk::TrackingVolume* currVol = &tvol;
2698
2699 // set tracking geometry in cache
2700 cache.setTrackingGeometry(*m_navigator,ctx);
2701 // arbitrary surface or destination layer ?
2702 // bool loopOverLayers = false;
2703 const Trk::Layer* destinationLayer =
2704 cache.m_trackingGeometry->associatedLayer(sf.center());
2705 // if ( destinationLayer ) loopOverLayers = true;
2706
2707 // initial distance to surface
2708 const Trk::DistanceSolution distSol = sf.straightLineDistanceEstimate(
2709 nextParameters->position(), dir * nextParameters->momentum().normalized());
2710 if (distSol.numberOfSolutions() > 0) {
2711 dist = distSol.first();
2712 } else {
2713 dist = distSol.toPointOfClosestApproach();
2714 }
2715
2716 if (destinationLayer && destinationLayer->isOnLayer(nextParameters->position())) {
2717 ATH_MSG_DEBUG(" [-] Already at destination layer, distance:" << dist);
2719 prop.propagate(ctx, *nextParameters, sf, dir, bcheck, m_fieldProperties,
2720 particle, false, currVol));
2721
2722 if (fwd) {
2723 return fwd;
2724 }
2725 Trk::PropDirection const oppDir =
2727 return cache.m_ownedPtrs.push(
2728 prop.propagate(ctx, *nextParameters, sf, oppDir, bcheck,
2729 m_fieldProperties, particle, false, currVol));
2730 }
2731
2732 if (std::abs(dist) < m_tolerance) {
2733 ATH_MSG_DEBUG(" [-] Already at the destination surface.");
2734
2735 if (dist >= 0.) {
2736 return cache.m_ownedPtrs.push(prop.propagate(ctx, *nextParameters, sf, dir,
2737 bcheck, m_fieldProperties,
2738 particle, false, currVol));
2739 }
2740 Trk::PropDirection const oppDir =
2742 return cache.m_ownedPtrs.push(
2743 prop.propagate(ctx, *nextParameters, sf, oppDir, bcheck,
2744 m_fieldProperties, particle, false, currVol));
2745 }
2746 if (dist < 0.) {
2747 ATH_MSG_DEBUG(" [!] Initial 3D-distance to the surface negative ("
2748 << dist << ") -> skip extrapolation.");
2750 return {};
2751 }
2752
2753 ATH_MSG_DEBUG(" [+] Initial 3D-distance to destination - d3 = " << dist);
2754
2755 // loop over material layers till
2756 // a/ destination layer found (accept solutions outside surface boundary)
2757 // b/ boundary reached
2758 // c/ negative distance to destination surface( propagate directly to the surface )
2759
2760 // ---------------------------- main loop over next material layers
2761 // used only to check whether parametersAtBoundary
2762 Trk::TrackParameters* last_boundary_parameters = nullptr;
2763
2764 while (nextParameters) {
2765 const Trk::BoundaryCheck& bchk = false;
2767 ctx, cache, prop, nextParameters, &sf, currVol, dir, bchk, particle, matupmode);
2768 if (onNextLayer) { // solution with the destination surface ?
2769 // isOnSurface dummy for Perigee, use straightline distance estimate instead
2770 // if ( sf.isOnSurface(onNextLayer->position(),bchk,m_tolerance,m_tolerance) ) {
2771 const Trk::DistanceSolution distSol = sf.straightLineDistanceEstimate(
2772 onNextLayer->position(), dir * onNextLayer->momentum().normalized());
2773 const double currentDistance = (distSol.numberOfSolutions() > 0)
2774 ? distSol.absClosest()
2775 : std::abs(distSol.toPointOfClosestApproach());
2776 if (currentDistance <= m_tolerance &&
2777 sf.isOnSurface(onNextLayer->position(), bchk, m_tolerance, m_tolerance)) {
2779 if (!bcheck || sf.isOnSurface(onNextLayer->position(), bcheck, m_tolerance, m_tolerance)) {
2780 if (sf.type() != onNextLayer->associatedSurface().type()) {
2781 ATH_MSG_DEBUG("mismatch in destination surface type:"
2782 << static_cast<int>(sf.type())
2783 << "," << static_cast<int>(onNextLayer->associatedSurface().type())
2784 << ":distance to the destination surface:" << currentDistance);
2786 ctx, *onNextLayer, sf, dir, bchk, m_fieldProperties, particle));
2787 return cParms;
2788 }
2789 return onNextLayer;
2790 }
2791 return {};
2792 }
2793 } else {
2794 // world boundary ?
2796 nextParameters = onNextLayer;
2797 break;
2798 }
2800 || cache.m_status != Cache::kContinue) {
2801 return {};
2802 }
2803
2804 // static volume boundary: check distance to destination
2805 const Trk::DistanceSolution distSol = sf.straightLineDistanceEstimate(
2807 dir * cache.m_parametersAtBoundary.nextParameters->momentum().normalized());
2808 if (distSol.numberOfSolutions() > 0) {
2809 dist = distSol.first();
2810 } else {
2811 dist = distSol.toPointOfClosestApproach();
2812 }
2813 if (dist < 0.) {
2815 return {};
2816 } if (cache.m_parametersAtBoundary.nextVolume &&
2821 if (last_boundary_parameters &&
2822 last_boundary_parameters == cache.m_parametersAtBoundary.nextParameters) {
2824 " [!] Already tried parameters at boundary -> exit: pos="
2826 << " momentum="
2827 << momentumOutput(cache.m_parametersAtBoundary.nextParameters->momentum()));
2829 return {};
2830 }
2831 onNextLayer = cache.m_parametersAtBoundary.nextParameters;
2832 last_boundary_parameters = cache.m_parametersAtBoundary.nextParameters;
2833 ATH_MSG_DEBUG(" [+] Try parameters at boundary: pos="
2835 << " momentum="
2836 << momentumOutput(cache.m_parametersAtBoundary.nextParameters->momentum()));
2837 }
2838 currVol = cache.m_parametersAtBoundary.nextVolume;
2839 }
2840 }
2841 nextParameters = onNextLayer;
2842 } // end loop over material layers
2843
2844 // boundary reached , return to the main loop
2845 ATH_MSG_DEBUG(" [+] extrapolateWithinDetachedVolumes(...) reached static boundary, return to "
2846 "the main loop.");
2847 return nextParameters;
2848}
2849
2850void
2852 Cache& cache,
2853 const IPropagator& prop,
2855 const Layer* assocLayer,
2856 const TrackingVolume& tvol,
2857 PropDirection dir,
2858 const BoundaryCheck& bcheck,
2859 ParticleHypothesis particle,
2860 MaterialUpdateMode matupmode) const
2861{
2862 // ---> C) detached volumes exist
2863 if (!tvol.confinedDetachedVolumes().empty()) {
2865 " [!] toVolumeBoundaryDetachedVolumes(...) with confined detached volumes? This should "
2866 "not happen ! volume name and signature: "
2867 << tvol.volumeName() << ":" << tvol.geometrySignature());
2868 }
2869 // ---> A) static layers exist
2871 ctx, cache, true, prop, parm, assocLayer, tvol, dir, bcheck, particle, matupmode));
2872 if (inside_volume_static_layer && cache.m_parametersAtBoundary.navParameters) {
2873 ATH_MSG_VERBOSE(" [+] Boundary intersection - at "
2875 }
2876}
2877
2880 Cache& cache,
2881 bool toBoundary,
2882 const IPropagator& prop,
2884 const Trk::Layer* assocLayer,
2885 const TrackingVolume& tvol,
2886 PropDirection dir,
2887 const BoundaryCheck& bcheck,
2888 ParticleHypothesis particle,
2889 MaterialUpdateMode matupmode) const
2890{
2891 // method sequence output ---------------------------------
2892 ++cache.m_methodSequence;
2893 // the next volume as given from the navigator
2894 const Trk::TrackingVolume* nextVolume = nullptr;
2895 // initialization
2896 // nextParameters : parameters to be used for the extrapolation stream
2897 Trk::CacheOwnedPtr<Trk::TrackParameters> nextParameters(parm);
2898 // navParameters : parameters to be used for the navigation stream (if possible, start from
2899 // boundary parameters)
2902 : nextParameters);
2903
2904 // adjust the radial scaling for the layer search, this is for inwards vs. outwards moving
2905 const double rPos = parm->position().perp();
2906 double rComponent = parm->momentum().normalized().perp();
2907 // numerical stability
2908 rComponent = rComponent < 10e-5 ? 10e-5 : rComponent;
2909 // a special case for closed cylinders, check if rScalor is not below numerical tolerance
2910 double rScalor = (toBoundary && tvol.boundarySurfaces().size() == 3) ? 2. * rPos / rComponent
2911 : 0.5 * rPos / rComponent;
2912 rScalor = rScalor * rScalor < 10e-10 ? 0.1 : rScalor;
2913
2914 // output and fast exit if the volume does not have confined layers
2915 if (toBoundary) {
2916 ATH_MSG_VERBOSE("S-[" << cache.m_methodSequence
2917 << "] insideVolumeStaticLayers(...) to volume boundary of '"
2918 << tvol.volumeName() << "'");
2919 } else { // to destination surface
2920 ATH_MSG_VERBOSE("S-[" << cache.m_methodSequence
2921 << "] insideVolumeStaticLayers(...) to destination surface in '"
2922 << tvol.volumeName() << "'");
2923 // no layer case - just do the extrapolation to the destination surface
2924 if (!tvol.confinedLayers()) {
2926 " [+] Volume does not contain layers, just propagate to destination surface.");
2927 // the final extrapolation to the destinationLayer
2928 nextParameters = cache.m_ownedPtrs.push(
2929 prop.propagate(ctx, *parm, *cache.m_destinationSurface, dir, bcheck,
2930 m_fieldProperties, particle));
2931 if (!nextParameters) {
2932 nextParameters = cache.m_ownedPtrs.push(prop.propagate(
2933 ctx, *parm, *cache.m_destinationSurface, Trk::anyDirection, bcheck,
2934 m_fieldProperties, particle));
2935 }
2936 return nextParameters;
2937 }
2938 }
2939
2940 // print out the perpendicular direction best guess parameters
2942 " [+] Perpendicular direction of the track : " << radialDirection(*navParameters, dir));
2943 // check whether to do a postupdate with the assoicated Layer
2944 const Trk::Layer* associatedLayer = assocLayer;
2945 // chache the assocLayer given, because this may be needed for the destination layer
2946 const Trk::Layer* assocLayerReference = assocLayer;
2947
2948 // the exit face of the last volume
2950
2951 // ============================ RESOLVE DESTINATION / STARTPOINT ============================
2952 // (1) ASSOCIATION
2953 const Trk::Layer* destinationLayer = nullptr;
2954 // will be only executed if directive is not to go to the boundary
2955 if (!toBoundary) {
2956 destinationLayer = cache.m_destinationSurface->associatedLayer();
2957 if (!destinationLayer) { // (2) RECALL (very unlikely) // (3) GLOBAL SEARCH
2958 destinationLayer =
2959 (cache.m_recallSurface == cache.m_destinationSurface &&
2961 ? cache.m_recallLayer
2963 }
2964 if (destinationLayer) {
2965 ATH_MSG_VERBOSE(" [+] Destination layer found - with "
2966 << layerRZoutput(*destinationLayer));
2967 }
2968 } // destination layer only gather if extrapolation does not go to boundary
2969
2970 // The update on the starting layer if necessary ----------------------------------
2971 // - only done in static volume setup
2972 // - only done if required
2973 // - only done if the parameter is on the layer
2974 // - only if no volume skip has been done
2975 // - only if associated layer is not destination layer (and both exist)
2976 if (!m_skipInitialLayerUpdate && associatedLayer && associatedLayer != destinationLayer &&
2977 associatedLayer->layerMaterialProperties() && tvol.confinedLayers()) {
2979 " [+] In starting volume: check for eventual necessary postUpdate and overlapSearch.");
2980
2981 // check if the parameter is on the layer
2982 const Trk::Layer* parsLayer = nextParameters->associatedSurface().associatedLayer();
2983 if ((parsLayer && parsLayer == associatedLayer) ||
2984 associatedLayer->surfaceRepresentation().isOnSurface(parm->position(),
2985 false,
2986 0.5 * associatedLayer->thickness(),
2987 0.5 * associatedLayer->thickness())) {
2988 // call the overlap search for the starting layer if asked for
2989 if (cache.m_parametersOnDetElements && associatedLayer->surfaceArray()) {
2990 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on start layer.");
2991 overlapSearch(ctx, cache, prop, parm, nextParameters, *associatedLayer,
2992 tvol, dir, bcheck, particle, true);
2993 }
2994
2995 // the post-update is valid
2996 ATH_MSG_VERBOSE(" [+] Calling postUpdate on inital track parameters.");
2997 // do the post-update according to the associated Layer - parameters are
2998 // either (&parm) or newly created ones chose current updator
2999
3000 const IMaterialEffectsUpdator* currentUpdator = subMaterialEffectsUpdator(tvol);
3001 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
3003
3004 if (currentUpdator) {
3005 nextParameters = cache.m_ownedPtrs.push(currentUpdator->postUpdate(
3006 currentUpdatorCache, *nextParameters, *associatedLayer, dir,
3007 particle, matupmode));
3008 }
3009 // collect the material : either for extrapolateM or for the valdiation
3010 if (nextParameters && cache.m_matstates) {
3012 ctx, cache, prop, nextParameters, *associatedLayer, tvol, dir, particle);
3013 }
3014 if (nextParameters && nextParameters != parm) {
3015 } else if (!m_stopWithUpdateZero) { // re-assign the start parameters
3016 // @TODO condition correct ?
3017 nextParameters = parm;
3018 } else {
3019 ATH_MSG_VERBOSE(" [-] Initial postUpdate killed track.");
3021 cache.resetRecallInformation();
3022 return {};
3023 }
3024 }
3025 } else {
3026 assocLayer = nullptr; // reset the provided Layer in case no postUpdate happened: search a new one
3027 // for layer2layer start
3028 }
3029 // ============================ RESOLVE STARTPOINT =============================
3030 // only if you do not have an input associated Layer
3031 // - this means that a volume step has been done
3032
3033 if (!associatedLayer) {
3034 ATH_MSG_VERBOSE(" [+] Volume switch has happened, searching for entry layers.");
3035 // reset the exitFace
3036 exitFace = cache.m_parametersAtBoundary.exitFace;
3037 // Step [1] Check for entry layers --------------------------
3038 associatedLayer = tvol.associatedLayer(navParameters->position());
3039 if (associatedLayer && associatedLayer->layerMaterialProperties()) {
3040 // --------------------------------------------------------
3041 ATH_MSG_VERBOSE(" [+] Entry layer to volume found with "
3042 << layerRZoutput(*associatedLayer));
3043 // try to go to the entry Layer first - do not delete the parameters (garbage collection done
3044 // by method)
3045 // - set entry flag
3046 auto [new_track_parm, killed] = extrapolateToIntermediateLayer(
3047 ctx, cache, prop, parm, *associatedLayer, tvol, dir, bcheck, particle, matupmode);
3048 nextParameters = new_track_parm;
3049 // -------------------------------------------------------
3050 if (m_stopWithUpdateZero && killed) {
3051 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
3052 // set the new boundary information
3054 cache.resetRecallInformation();
3055 return {};
3056 } if (cache.m_boundaryVolume && nextParameters &&
3057 !cache.m_boundaryVolume->inside(nextParameters->position())) {
3058 ATH_MSG_VERBOSE(" [+] Parameter outside the given boundary/world stopping loop.");
3059 // set the new boundary information
3061 cache.resetRecallInformation();
3062 return {};
3063 }
3064 // --------------------------------------------------------
3065 if (nextParameters) {
3066 ATH_MSG_VERBOSE(" [+] Entry layer successfully hit - at "
3067 << positionOutput(nextParameters->position()));
3068 }
3069 // --------------------------------------------------------
3070 // check whether it worked or not
3071 if (!nextParameters) {
3072 nextParameters = parm;
3073 }
3074 }
3075 }
3076
3077 // Step [2] Associate the starting point to the layer ------------------------------------------
3078 // if an action has been taken, the nextParameters are not identical with the provided parameters
3079 // anymore
3080 if (nextParameters != parm) {
3081 navParameters = nextParameters;
3082 }
3083 // only associate the layer if the destination layer is not the assigned reference
3084 if (destinationLayer != assocLayerReference || toBoundary) {
3085 // get the starting layer for the layer - layer loop
3086 associatedLayer = assocLayer ? assocLayer : tvol.associatedLayer(navParameters->position());
3087 // ignore closest material layer if it is equal to the initially given layer (has been handled
3088 // by the post update )
3089 associatedLayer =
3090 (associatedLayer && associatedLayer == assocLayerReference)
3091 ? associatedLayer->nextLayer(navParameters->position(),
3092 dir * rScalor * navParameters->momentum().normalized())
3093 : associatedLayer;
3094 }
3095
3096 if (associatedLayer) {
3097 ATH_MSG_VERBOSE(" [+] Associated layer at start with " << layerRZoutput(*associatedLayer));
3098 }
3099
3100 // the layer to layer step and the final destination layer step can be done
3101 if (destinationLayer || toBoundary) {
3102 // the layer to layer step only makes sense here
3103 if (associatedLayer && associatedLayer != destinationLayer) {
3104 // screen output
3105 ATH_MSG_VERBOSE(" [+] First layer for layer2layer with "
3106 << layerRZoutput(*associatedLayer));
3107
3108 // now do the loop from the associatedLayer to one before the destinationLayer
3110 ctx, cache, prop, nextParameters, tvol, associatedLayer,
3111 destinationLayer, navParameters, dir, bcheck, particle,
3112 matupmode);
3113 // kill the track when the update ----------------------
3114 if (m_stopWithUpdateZero && !updateNext) {
3115 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
3116 // set the new boundary information
3118 cache.resetRecallInformation();
3119 return {};
3120 } if (cache.m_boundaryVolume && updateNext &&
3121 !cache.m_boundaryVolume->inside(updateNext->position())) {
3122 ATH_MSG_VERBOSE(" [+] Parameter outside the given boundary/world stopping loop.");
3123 // set the new boundary information
3125 cache.resetRecallInformation();
3126 return {};
3127 }
3128 // the fallback if only one step was done - solve cleaner
3129 if (updateNext) {
3130 nextParameters = updateNext;
3131 }
3132 }
3133 // Case Ia: To Destination after LayerToLayer sequence
3134 if (!toBoundary) {
3135 // the final extrapolation to the destinationLayer
3136 nextParameters = extrapolateToDestinationLayer(
3137 ctx, cache, prop, nextParameters, *cache.m_destinationSurface,
3138 *destinationLayer, tvol, assocLayerReference, dir, bcheck, particle,
3139 matupmode);
3140
3141 // set the recallInformation <- everything went fine
3142 cache.setRecallInformation( *cache.m_destinationSurface, *destinationLayer, tvol);
3143 // done
3144 return nextParameters;
3145 }
3146 // -----------------------------------------------------------------------------------
3147 // Case Ib: To Destination directly since no destination layer has been found
3148 } else if (!toBoundary) {
3149 nextParameters = cache.m_ownedPtrs.push(
3150 prop.propagate(ctx, *nextParameters, *cache.m_destinationSurface, dir,
3151 bcheck, m_fieldProperties, particle));
3152 // job done: cleanup and go home
3153 // reset the recallInformation
3154 cache.resetRecallInformation();
3155 // return the directly extrapolated ones
3156 return nextParameters;
3157 }
3158
3159 // the reset to the initial in case the extrapolationFromLayerToLayer
3160 if (!nextParameters) {
3161 nextParameters = parm;
3162 }
3163
3164 // start the search with the simplest possible propagator
3165 unsigned int navprop = 0;
3166
3167 Trk::CacheOwnedPtr<Trk::TrackParameters> bParameters= nullptr;
3168 if (m_numOfValidPropagators != INVALIDPROPAGATORS) {
3169 // loop over propagators to do the search
3170 while (navprop < m_numOfValidPropagators) {
3171 const IPropagator* navPropagator = &(*m_propagators[navprop]);
3172
3173 // we veto the navigaiton parameters for calo-volumes with calo dynamic
3174 const bool vetoNavParameters = false; //
3175 // the next Parameters are usually better, because they're closer to the
3176 // boundary
3177 // --- in the initial volume (assocLayerReference!=0), the parm are good if
3178 // no action taken
3179 if (nextParameters != parm || assocLayerReference) {
3180 navParameters = nextParameters;
3181 } else {
3182 navParameters = (cache.m_parametersAtBoundary.navParameters && !vetoNavParameters)
3184 : nextParameters;
3185 }
3186
3187 ATH_MSG_VERBOSE(" [+] Starting next boundary search from "
3188 << positionOutput(navParameters->position()));
3189 ATH_MSG_VERBOSE(" [+] Starting next boundary search with "
3190 << momentumOutput(navParameters->momentum()));
3191
3192 // get the new navigaiton cell from the Navigator
3193 Trk::NavigationCell nextNavCell =
3194 m_navigator->nextTrackingVolume(ctx, *navPropagator, *navParameters, dir, tvol);
3195 nextVolume = nextNavCell.nextVolume;
3196
3197 navParameters =
3198 cache.m_ownedPtrs.push(std::move(nextNavCell.parametersOnBoundary));
3199 bParameters = navParameters;
3200 // set the new exit Cell
3201 exitFace = nextNavCell.exitFace;
3202 navprop++;
3203 if (nextVolume) {
3204 break;
3205 }
3206 }
3207 } else {
3208 Trk::NavigationCell nextNavCell =
3209 m_navigator->nextTrackingVolume(ctx, prop, *navParameters, dir, tvol);
3210
3211 nextVolume = nextNavCell.nextVolume;
3212 navParameters = cache.m_ownedPtrs.push(std::move(nextNavCell.parametersOnBoundary));
3213 bParameters = navParameters;
3214 // set the new exit Cell
3215 exitFace = nextNavCell.exitFace;
3216 }
3217
3218 if (!nextVolume && !cache.m_parametersOnDetElements) {
3219 ATH_MSG_DEBUG(" [-] Cannot find nextVolume of TrackingVolume: " << tvol.volumeName());
3220 if (navParameters) {
3221 ATH_MSG_VERBOSE(" Starting Parameters : " << navParameters);
3222 } else {
3223 ATH_MSG_VERBOSE(" Starting Parameters not defined.");
3224 }
3225 // reset the recall information as it is invalid
3226 cache.resetRecallInformation();
3227 }
3228
3229 if (bParameters && bParameters->associatedSurface().materialLayer()) {
3230 ATH_MSG_VERBOSE(" [+] parameters on BoundarySurface with material.");
3232
3233 const IMaterialEffectsUpdator* currentUpdator = m_subupdaters[tvol.geometrySignature()];
3234 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
3236
3237 if (currentUpdator) {
3238 bParameters = cache.m_ownedPtrs.push(currentUpdator->update(
3239 currentUpdatorCache, bParameters,
3240 *(bParameters->associatedSurface().materialLayer()), dir, particle,
3241 matupmode));
3242 }
3243 // collect the material
3244 if (bParameters && cache.m_matstates) {
3246 ctx, cache, prop, bParameters,
3247 *(bParameters->associatedSurface().materialLayer()), tvol, dir,
3248 particle);
3249 }
3250 navParameters = bParameters;
3251 }
3252 }
3253
3254 // set the new boundary information
3256 nextVolume, nextParameters, navParameters, exitFace);
3257
3258 // return the navParameters
3259 return navParameters;
3260}
3261
3262// ----------------------- The private Layer extrapolation methods --------------------------
3263
3266 Cache& cache,
3267 const IPropagator& prop,
3269 const TrackingVolume& tvol,
3270 const Layer* startLayer,
3271 const Layer* destinationLayer,
3273 PropDirection dir,
3274 const BoundaryCheck& bcheck,
3275 ParticleHypothesis particle,
3276 MaterialUpdateMode matupmode) const
3277{
3278 // method sequence output ---------------------------------
3279 ++cache.m_methodSequence;
3280 ATH_MSG_DEBUG("S-[" << cache.m_methodSequence << "] extrapolateFromLayerToLayer(...) in '"
3281 << tvol.volumeName() << "'. ");
3282
3283 // initialize the loop
3284 const Trk::Layer* nextLayer = startLayer;
3285 // avoiding straight loops and oszillations
3286 const Trk::Layer* lastLayer = nullptr;
3287 const Trk::Layer* previousLayer = nullptr;
3288 // pars & fallback
3290 Trk::CacheOwnedPtr<Trk::TrackParameters> navParameters = navParm;
3291 // avoid initial perpendicular check if:
3292 // - navParameters and currPar have different perpendicular direction (resolved in navigaiton)
3293 bool perpCheck = radialDirection(*currPar, dir) * radialDirection(*navParameters, dir) > 0;
3294
3295 // break conditions: --------- handeled by layerAttempts
3296 unsigned int failedAttempts = 0;
3297
3298 // get the max attempts from the volume
3299 const unsigned int layersInVolume =
3300 tvol.confinedLayers() ? tvol.confinedLayers()->arrayObjects().size() : 0;
3301 // set the maximal attempts to at least m_initialLayerAttempts
3302 const unsigned int maxAttempts =
3303 std::max(m_initialLayerAttempts.value(),
3304 static_cast<unsigned int>(layersInVolume * 0.5));
3305
3306 ATH_MSG_VERBOSE(" [+] Maximum number of failed layer attempts: " << maxAttempts);
3307
3308 // conditions for the loop are :
3309 // - nextLayer exists
3310 // - nextLayer is not the previous one, Exception : inbound cosmics
3311 // - nextLayer is not the last layer, Exception: formerly inbound cosmics
3312 // - nextLayer is not the destination layer
3313 // - the number of attempts does not exceed a set maximum
3314
3315 while (nextLayer && nextLayer != previousLayer && nextLayer != lastLayer &&
3316 nextLayer != destinationLayer && failedAttempts < maxAttempts) {
3317 // screen output
3318 ATH_MSG_VERBOSE(" [+] Found next "
3319 << ((nextLayer->layerMaterialProperties() ? "material layer - with "
3320 : "navigation layer with "))
3321 << layerRZoutput(*nextLayer));
3322
3323 // skip the navigation layers
3324 if (nextLayer->layerMaterialProperties() ||
3325 (cache.m_parametersOnDetElements && nextLayer->surfaceArray())) {
3326 // the next step - do not delete the parameters (garbage collection done by method)
3327 auto [new_track_parm, killed] = extrapolateToIntermediateLayer(
3328 ctx, cache, prop, currPar, *nextLayer, tvol, dir, bcheck, particle,
3329 matupmode, perpCheck);
3331 new_track_parm);
3332 // previous and last layer setting for loop and oscillation protection
3333 previousLayer = lastLayer;
3334 lastLayer = nextLayer;
3335 // the breaking condition ------------------------------------
3336 // check killed first because if killed is true nexPar will be invalid.
3337 if (killed) {
3338 ATH_MSG_VERBOSE(" [+] Material update killed the track parameters - return 0");
3339 // kill the track - Fatras case
3340 return {};
3341 } if (!nextPar) {
3342 ++failedAttempts;
3343 ++m_layerSwitched; // record for statistics output
3344 // reset until break condition is fullfilled
3345 } else if (cache.m_boundaryVolume && !cache.m_boundaryVolume->inside(nextPar->position())) {
3346 ATH_MSG_VERBOSE(" [+] Parameter outside the given boundary/world stopping loop.");
3347 // set the new boundary information
3348 return nextPar;
3349 } else { // reset the failed attempts
3350 ATH_MSG_VERBOSE(" [+] Intersection successful: allowing for " << maxAttempts
3351 << " more failed attempt.");
3352 failedAttempts = 0;
3353 // but a hit sets the max attempts to m_successiveLayerAttempts => navigation machine
3354 // started ! maxAttempts = m_successiveLayerAttempts; new navParameters are currPar
3355 navParameters = nextPar;
3356 currPar = nextPar;
3357 // enforce the perpendicular check
3358 perpCheck = true;
3359 }
3360 }
3361
3362 // cache of radiatl direction and next layer request
3363 nextLayer =
3364 nextLayer->nextLayer(navParameters->position(), dir * navParameters->momentum().normalized());
3365
3366 // screen output
3367 if (!nextLayer) {
3368 ATH_MSG_VERBOSE(" [+] No next Layer provided by the previous layer -> stop of layer2layer");
3369 }
3370 }
3371 if (failedAttempts >= maxAttempts) {
3372 ATH_MSG_VERBOSE(" [-] Maximum number of Attempts triggered in '" << tvol.volumeName() << "'.");
3373 }
3374
3375 // return the result
3376 return currPar;
3377}
3378
3381 Cache& cache,
3382 const IPropagator& prop,
3384 const Surface& sf,
3385 const Layer& lay,
3386 const TrackingVolume& tvol,
3387 const Layer* startLayer,
3388 PropDirection dir,
3389 const BoundaryCheck& bcheck,
3390 ParticleHypothesis particle,
3391 MaterialUpdateMode matupmode) const
3392{
3393 // method sequence output ---------------------------------
3394 ++cache.m_methodSequence;
3395 ATH_MSG_DEBUG("S-[" << cache.m_methodSequence << "] extrapolateToDestinationLayer(...) in '"
3396 << tvol.volumeName() << "'.");
3397 // start is destination layer -> on layer navigation, take care
3398 const bool startIsDestLayer = startLayer == (&lay);
3399
3400 // get the Parameters on the destination surface
3401 Trk::CacheOwnedPtr<Trk::TrackParameters> destParameters = cache.m_ownedPtrs.push(prop.propagate(
3402 ctx, *parm, sf, dir, bcheck, MagneticFieldProperties(), particle));
3403 // fallback to anyDirection
3404 if (!destParameters) {
3405 destParameters = cache.m_ownedPtrs.push(
3406 prop.propagate(ctx, *parm, sf, Trk::anyDirection, bcheck,
3407 m_fieldProperties, particle));
3408 }
3409
3410 // return the pre-updated ones
3411 const IMaterialEffectsUpdator* currentUpdator = subMaterialEffectsUpdator(tvol);
3412 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
3414
3415 Trk::CacheOwnedPtr<Trk::TrackParameters> preUpdatedParameters = nullptr;
3416 if (currentUpdator && destParameters && !startIsDestLayer) {
3417 preUpdatedParameters = cache.m_ownedPtrs.push(currentUpdator->preUpdate(
3418 currentUpdatorCache, destParameters, lay, dir, particle, matupmode));
3419 } else {
3420 preUpdatedParameters = destParameters;
3421 }
3422
3423 // collect the material : either for extrapolateM or for the valdiation
3424 if (cache.m_matstates && preUpdatedParameters &&
3425 currentUpdator && !startIsDestLayer &&
3426 lay.preUpdateMaterialFactor(*destParameters, dir) >= 0.01) {
3428 ctx, cache, prop, preUpdatedParameters, lay, tvol, dir, particle);
3429 }
3430
3431 // call the overlap search on the destination parameters - we are at the surface already
3432 if (cache.m_parametersOnDetElements && preUpdatedParameters && lay.surfaceArray()) {
3433 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on destination layer.");
3434 // start is destination layer
3435 overlapSearch(ctx, cache, prop, parm, preUpdatedParameters, lay, tvol, dir,
3436 bcheck, particle, startIsDestLayer);
3437 }
3438
3439 if (preUpdatedParameters) {
3440 ATH_MSG_VERBOSE(" [+] Destination surface successfully hit.");
3441 }
3442
3443 // return the pre-updated parameters (can be 0 though)
3444 return preUpdatedParameters;
3445}
3446
3447std::pair<Trk::CacheOwnedPtr<Trk::TrackParameters>, bool>
3449 Cache& cache,
3450 const IPropagator& prop,
3452 const Layer& lay,
3453 const TrackingVolume& tvol,
3454 PropDirection dir,
3455 const BoundaryCheck& bcheck,
3456 ParticleHypothesis particle,
3457 MaterialUpdateMode matupmode,
3458 bool doPerpCheck) const
3459{
3460 // method sequence output ---------------------------------
3461 ++cache.m_methodSequence;
3462 ATH_MSG_DEBUG("S-[" << cache.m_methodSequence << "] to extrapolateToIntermediateLayer(...) layer "
3463 << lay.layerIndex() << " in '" << tvol.volumeName() << "'.");
3464
3465 // chose the current updator
3466 const IMaterialEffectsUpdator* currentUpdator = subMaterialEffectsUpdator(tvol);
3467 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
3469 // then go onto the Layer
3470 Trk::CacheOwnedPtr<Trk::TrackParameters> parsOnLayer = nullptr;
3471
3472 parsOnLayer = cache.m_ownedPtrs.push(
3473 prop.propagate(ctx, *parm, lay.surfaceRepresentation(), dir, true,
3474 m_fieldProperties, particle));
3475
3476 // return if there is nothing to do
3477 if (!parsOnLayer) {
3478 return std::make_pair(nullptr, false);
3479 }
3480 // the layer has been intersected -----------------------------------------------------
3481 // check for radial direction change ----------------------------------------------
3482 int const rDirection = radialDirection(*parm, dir);
3483 int const newrDirection = radialDirection(*parsOnLayer, dir);
3484 if (newrDirection != rDirection && doPerpCheck) {
3485 // it is unfortunate that the cancelling could invalidate the material collection
3486 ATH_MSG_DEBUG(" [!] Perpendicular direction of track has changed -- checking");
3487 // reset the nextParameters if the radial change is not allowed
3488 // resetting is ok - since the parameters are in the garbage bin already
3489 if (!radialDirectionCheck(ctx, prop, *parm, *parsOnLayer, tvol, dir, particle)) {
3490 ATH_MSG_DEBUG(" [+] Perpendicular direction check cancelled this layer intersection.");
3491 return std::make_pair(Trk::CacheOwnedPtr<Trk::TrackParameters>(), false);
3492 }
3493 }
3494 // ----------------------------------------------------------------------------------
3495 ATH_MSG_VERBOSE(" [+] Layer intersection successful at "
3496 << positionOutput(parsOnLayer->position()));
3497 ATH_MSG_VERBOSE(" [+] Layer intersection successful with "
3498 << momentumOutput(parsOnLayer->momentum()));
3499
3500 // Fatras mode -----------------------------------------------------------------------
3501 if (cache.m_parametersOnDetElements && lay.surfaceArray()) {
3502 // ceck the parameters size before the search
3503 size_t const sizeBeforeSearch = cache.m_parametersOnDetElements->size();
3504 // perform the overlap Search on this layer
3505 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on intermediate layer.");
3506 overlapSearch(ctx, cache, prop, parm, parsOnLayer, lay, tvol, dir, bcheck, particle);
3507 size_t const sizeAfterSearch = cache.m_parametersOnDetElements->size();
3508 // the Fatras mode was successful -> postUpdate and garbage collection
3509 int const lastElement = (int)cache.m_parametersOnDetElements->size() - 1;
3510 // we have created hits in the vector
3511 if (lastElement >= 0 && sizeBeforeSearch < sizeAfterSearch) {
3512 // get the last element
3513 // it's ok to reassign parOnLayer as the pointer to the first one is in the garbage bin
3514 // already get the latest Fatras hit to start from this one
3515 if (!(*cache.m_parametersOnDetElements)[lastElement]) {
3516 throw std::logic_error("Invalid track parameters on det elements (lastElement)");
3517 }
3518 auto cloneInput = ((*cache.m_parametersOnDetElements)[lastElement])->uniqueClone();
3519 parsOnLayer = ((*cache.m_parametersOnDetElements)[lastElement]
3520 ? cache.m_ownedPtrs.push(std::move(cloneInput))
3521 : nullptr);
3522 ATH_MSG_DEBUG(" [+] Detector element & overlapSearch successful,"
3523 << " call update on last parameter on this layer.");
3524 }
3525 } // -------------------------- Fatras mode off -----------------------------------
3526
3527 // return the full-updated ones - may create a new object
3528 if (lay.layerMaterialProperties() && currentUpdator) {
3529 parsOnLayer = cache.m_ownedPtrs.push(currentUpdator->update(
3530 currentUpdatorCache, parsOnLayer, lay, dir, particle, matupmode));
3531 }
3532 // there are layers that have a surfaceArray but no material properties
3533 if (parsOnLayer && lay.layerMaterialProperties() && cache.m_matstates) {
3534 addMaterialEffectsOnTrack(ctx, cache, prop, parsOnLayer, lay, tvol, dir, particle);
3535 }
3536 // kill the track if the update killed the track
3537 // ------------------------------------------------
3538 if (!parsOnLayer && m_stopWithUpdateZero) {
3539 return std::make_pair(nullptr, true); // the indicator to kill the loopfrom material update
3540 }
3541 // ------------ the return of the parsOnLayer --- they're in the garbage bin already
3542 return std::make_pair(parsOnLayer, false);
3543}
3544
3545void
3546Trk::Extrapolator::overlapSearch(const EventContext& ctx,
3547 Cache& cache,
3548 const IPropagator& prop,
3551 const Layer& lay,
3552 const TrackingVolume& /*tvol*/,
3553 PropDirection dir,
3554 const BoundaryCheck& bcheck, // bcheck
3555 ParticleHypothesis particle,
3556 bool startingLayer) const
3557{
3558 // indicate destination layer
3559 const bool isDestinationLayer = (&parsOnLayer->associatedSurface() == cache.m_destinationSurface);
3560 // start and end surface for on-layer navigation
3561 // -> take the start surface if ther parameter surface is owned by detector element
3562 const Trk::Surface* startSurface =
3563 ((parm->associatedSurface()).associatedDetectorElement() && startingLayer)
3564 ? &(parm->associatedSurface())
3565 : nullptr;
3566 const Trk::Surface* endSurface = isDestinationLayer ? cache.m_destinationSurface : nullptr;
3567 // - the best detSurface to start from is the one associated to the detector element
3568 const Trk::Surface* detSurface = (parsOnLayer->associatedSurface()).associatedDetectorElement()
3569 ? &parsOnLayer->associatedSurface()
3570 : nullptr;
3571
3572 ATH_MSG_VERBOSE(" [o] OverlapSearch called " << (startSurface ? "with " : "w/o ") << "start, "
3573 << (endSurface ? "with " : "w/o ")
3574 << "end surface.");
3575
3576 if (!detSurface) {
3577 // of parsOnLayer are different from parm, then local position is safe, because the
3578 // extrapolation
3579 // to the detector surface has been done !
3580 detSurface = isDestinationLayer ? lay.subSurface(parsOnLayer->localPosition())
3581 : lay.subSurface(parsOnLayer->position());
3582 if (detSurface) {
3583 ATH_MSG_VERBOSE(" [o] Detector surface found through subSurface() call");
3584 } else {
3585 ATH_MSG_VERBOSE(" [o] No Detector surface found on this layer.");
3586 }
3587 } else {
3588 ATH_MSG_VERBOSE(" [o] Detector surface found through parameter on layer association");
3589 }
3590
3591 // indicate the start layer
3592 const bool isStartLayer = (detSurface && detSurface == startSurface);
3593
3594 // the temporary vector (might have to be ordered)
3595 TrackParametersUVector detParametersOnLayer;
3596 bool reorderDetParametersOnLayer = false;
3597 // the first test for the detector surface to be hit (false test)
3598 // - only do this if the parameters aren't on the surface
3599 // (i.e. search on the start layer or end layer)
3600 Trk::CacheOwnedPtr<Trk::TrackParameters> detParameters = nullptr;
3601 if (isDestinationLayer) {
3602 detParameters = parsOnLayer;
3603 } else if (isStartLayer) {
3604 detParameters = parm;
3605 } else if (detSurface) {
3606 detParameters = cache.m_ownedPtrs.push(
3607 prop.propagate(ctx, *parm, *detSurface, dir, false, m_fieldProperties, particle));
3608 }
3609
3610 // set the surface hit to true, it is anyway overruled
3611 bool surfaceHit = true;
3612 // circumvents pointer management
3613 // to allow using detParameters after detParameters.release()
3614 Trk::CacheOwnedPtr<Trk::TrackParameters> track_parm_for_overlap(detParameters);
3615 if (detParameters && !isStartLayer && !isDestinationLayer) {
3616 ATH_MSG_VERBOSE(" [o] First intersection with Detector surface: " << *detParameters);
3617 // for the later use in the overlapSearch
3618 surfaceHit = detParameters && detSurface ? detSurface->isOnSurface(detParameters->position())
3619 : 0; // ,bcheck) -creates problems on start layer;
3620 // check also for start/endSurface on this level
3621 surfaceHit = (surfaceHit && startSurface)
3622 ? ((detParameters->position() - parm->position())
3623 .dot(dir * parm->momentum().normalized()) > 0)
3624 : surfaceHit;
3625 surfaceHit =(surfaceHit && endSurface)
3626 ? ((detParameters->position() - parsOnLayer->position())
3627 .dot(dir * parsOnLayer->momentum().normalized()) < 0)
3628 : surfaceHit;
3629 // surface is hit within bounds (or at least with given boundary check
3630 // directive) -> it counts surface hit also survived start/endsurface search
3631 //
3632 // Convention for Fatras: always apply the full update on the last
3633 // parameters
3634 // of the gathered vector (no pre/post schema)
3635 // don't record a hit on the destination surface
3636 if (surfaceHit && detSurface != startSurface && detSurface != cache.m_destinationSurface) {
3637 ATH_MSG_VERBOSE(" [H] Hit with detector surface recorded ! ");
3638 // push into the temporary vector
3639 detParametersOnLayer.emplace_back(cache.m_ownedPtrs.move(detParameters));
3640 } else if (detParameters) {
3641 // no hit -> fill into the garbage bin
3643 " [-] Detector surface hit cancelled through bounds check or start/end surface check.");
3644 }
3645 }
3646
3647 // search for the overlap -------------------------------------------------
3648 if (track_parm_for_overlap) {
3649 // retrieve compatible subsurfaces
3650 std::vector<Trk::SurfaceIntersection> cSurfaces;
3651 size_t const ncSurfaces =
3652 lay.compatibleSurfaces(cSurfaces, *track_parm_for_overlap, Trk::anyDirection, bcheck, false);
3653
3654 // import from StaticEngine.icc
3655 if (ncSurfaces) {
3656 ATH_MSG_VERBOSE("found " << ncSurfaces << " candidate sensitive surfaces to test.");
3657 // now loop over the surfaces:
3658 // the surfaces will be sorted @TODO integrate pathLength propagation into this
3659
3660 auto overlapSurfaceHit = m_overlapSurfaceHit.buffer();
3661 for (auto& csf : cSurfaces) {
3662 // propagate to the compatible surface, return types are (pathLimit
3663 // failure is excluded by Trk::anyDirection for the moment):
3664 Trk::CacheOwnedPtr<Trk::TrackParameters> overlapParameters = cache.m_ownedPtrs.push(
3665 prop.propagate(ctx, *parm, *(csf.object), Trk::anyDirection, true,
3666 m_fieldProperties, particle));
3667
3668 if (overlapParameters) {
3669 ATH_MSG_VERBOSE(" [+] Overlap surface was hit, checking start/end surface condition.");
3670 // check on start / end surface for on-layer navigaiton action
3671
3672 surfaceHit = (startSurface) ? ((overlapParameters->position() - parm->position())
3673 .dot(dir * parm->momentum().normalized()) > 0)
3674 : true;
3675
3676 surfaceHit = (surfaceHit && endSurface)
3677 ? ((overlapParameters->position() - parsOnLayer->position())
3678 .dot(dir * parsOnLayer->momentum().normalized()) < 0)
3679 : surfaceHit;
3680
3681 if (surfaceHit) {
3682 ATH_MSG_VERBOSE(" [H] Hit with detector surface recorded !");
3683 // count the overlap Surfaces hit
3684 ++overlapSurfaceHit;
3685 // distinguish whether sorting is needed or not
3686 reorderDetParametersOnLayer = true;
3687 // push back into the temporary vector
3688 detParametersOnLayer.emplace_back(cache.m_ownedPtrs.move(overlapParameters));
3689 } else { // the parameters have been cancelled by start/end surface
3690 // no hit -> fill into the garbage bin
3692 " [-] Detector surface hit cancelled through start/end surface check.");
3693 }
3694 }
3695 } // loop over test surfaces done
3696 } // there are compatible surfaces
3697 } // ----------------------------------------------------------------------
3698
3699 // reorder the track parameters if neccessary, the overlap descriptor did not provide the ordered
3700 // surfaces
3701 if (reorderDetParametersOnLayer) {
3702 // sort to reference of incoming parameters
3703 Trk::TrkParametersComparisonFunction const parameterSorter(parm->position());
3704 sort(detParametersOnLayer.begin(), detParametersOnLayer.end(), parameterSorter);
3705 }
3706 assert(cache.m_parametersOnDetElements);
3707 if (cache.m_parametersOnDetElements->empty()) {
3708 *(cache.m_parametersOnDetElements) = std::move(detParametersOnLayer);
3709 } else {
3710 std::move(detParametersOnLayer.begin(), detParametersOnLayer.end(),
3711 std::back_inserter(*(cache.m_parametersOnDetElements)));
3712 }
3713}
3714
3715// ----------------------- The Initialization --------------------------
3718 Cache& cache,
3719 const IPropagator& prop,
3721 const Surface& sf,
3722 PropDirection dir,
3723 ParticleHypothesis particle,
3725 const Layer*& associatedLayer,
3726 const TrackingVolume*& associatedVolume,
3727 const TrackingVolume*& destVolume) const
3728{
3729 cache.setTrackingGeometry(*m_navigator, ctx);
3730 // output for initializeNavigation should be an eye-catcher
3731 if (!cache.m_destinationSurface) {
3732 ATH_MSG_DEBUG(" [I] initializeNaviagtion() -------------------------- ");
3733 cache.m_methodSequence = 0;
3734 } else {
3735 ATH_MSG_DEBUG(" [I] (re)initializeNaviagtion() ---------------------- ");
3736 }
3737
3738 Trk::PropDirection navigationDirection = dir;
3739 // only for the initial and not for the redoNavigation - give back the navigation direction
3740 if (!cache.m_destinationSurface) {
3742 " [I] Starting with Start Layer/Volume search: ------------------------------");
3743 ATH_MSG_VERBOSE(" [I] Destination surface : " << sf);
3744 // reset the boundary information
3746 // and set the destination surface
3747 cache.m_destinationSurface = (&sf);
3748 // prepare for screen output
3749 const char* startSearchType = "association";
3750
3751 // ---------------------------------- ASSOCIATED VOLUME ----------------------------------
3752 // 1 - TRY the association method
3753 const Trk::Surface* associatedSurface = &parm->associatedSurface();
3754 associatedLayer = (associatedSurface) ? associatedSurface->associatedLayer() : associatedLayer;
3755 associatedVolume =
3756 associatedLayer ? associatedLayer->enclosingTrackingVolume() : associatedVolume;
3757 // 2 - TRY the recall method -> only if association method didn't work
3758 // only if associated detector element exists to protect against dynamic surfaces
3759 if (!associatedVolume && associatedSurface && associatedSurface == cache.m_recallSurface &&
3760 associatedSurface->associatedDetectorElement()) {
3761 // statistics output
3763 associatedVolume = cache.m_recallTrackingVolume;
3764 associatedLayer = cache.m_recallLayer;
3765 // change the association type
3766 startSearchType = "recall";
3767 } else if (!associatedVolume) {
3768 // 3 - GLOBAL SEARCH METHOD
3770 // non-perigee surface
3771 cache.resetRecallInformation();
3772 associatedVolume = cache.volume(ctx,parm->position());
3773
3774 associatedLayer =
3775 (associatedVolume) ? associatedVolume->associatedLayer(parm->position()) : nullptr;
3776
3777 // change the association type
3778 startSearchType = "global search";
3779
3780 // ---------------------------------- ASSOCIATED STATIC VOLUME
3781 // -------------------------------------- this is not necessary for ( association & recall )
3782 const Trk::TrackingVolume* lowestStaticVol =
3783 cache.m_trackingGeometry->lowestStaticTrackingVolume(parm->position());
3784
3785 if (lowestStaticVol && lowestStaticVol != associatedVolume) {
3786 associatedVolume = lowestStaticVol;
3787 }
3788 // ---------------------------------------------------------------------------
3789 } else {
3791 }
3792
3793 // verify if not exit point from associated volume
3794 if (associatedVolume && navigationDirection != Trk::anyDirection) {
3795 const Trk::TrackingVolume* nextAssVol = nullptr;
3796 if (m_navigator->atVolumeBoundary(parm, associatedVolume, dir, nextAssVol,
3797 m_tolerance) &&
3798 nextAssVol != associatedVolume) {
3799 if (nextAssVol) {
3800 associatedVolume = nextAssVol;
3801 } else {
3802 ATH_MSG_WARNING(" [X] Navigation break occurs in volume "
3803 << associatedVolume->volumeName() << " no action taken");
3804 }
3805 }
3806 }
3807 // ---------------- anyDirection given : navigation direction has to be estimated ---------
3808 if (navigationDirection == Trk::anyDirection) {
3810 " [I] 'AnyDirection' has been chosen: approaching direction must be determined.");
3811
3812 // refParameters = prop.propagateParameters(parm,sf,dir,false,*associatedVolume);
3813 refParameters = cache.m_ownedPtrs.push(prop.propagateParameters(
3814 ctx, *parm, sf, dir, false, m_fieldProperties, particle, false,
3815 associatedVolume));
3816 // chose on projective method
3817 if (refParameters) {
3818 // check the direction on basis of a vector projection
3819 const Amg::Vector3D surfaceDir(refParameters->position() - parm->position());
3820 if (surfaceDir.dot(parm->momentum()) > 0.) {
3821 navigationDirection = Trk::alongMomentum;
3822 } else {
3823 navigationDirection = Trk::oppositeMomentum;
3824 }
3825
3826 // really verbose statement, but needed for debugging
3827 ATH_MSG_VERBOSE(" [+] Approaching direction determined as: "
3828 << ((navigationDirection < 0) ? "oppositeMomentum." : "alongMomentum"));
3829 } else {
3831 " [+] Approaching direction could not be determined, they remain: anyDirection.");
3832 }
3833 }
3834 ATH_MSG_VERBOSE(" [I] Starting Information gathered through : " << startSearchType << ".");
3835 }
3836 // -----------------------------------------------------------------
3837
3838 // ---------------------------------- DESTINATION VOLUME ----------------------------------
3839 // only do it if sf is not the reference Surface
3840 ATH_MSG_VERBOSE(" [I] Starting with destination Volume search: -----------------------------");
3841
3842 if ((&sf) != (m_referenceSurface.get())) {
3843 // (1) - TRY the association method
3844 destVolume = (sf.associatedLayer()) ? sf.associatedLayer()->enclosingTrackingVolume() : nullptr;
3845 // for the summary output
3846 std::string destinationSearchType = "association";
3847 if (destVolume) {
3849 }
3850 // (2) - RECALL
3851 // only if associated detector element exists to protect against dynamic surfaces
3852 if (!destVolume && ((&sf) == cache.m_recallSurface) && sf.associatedDetectorElement()) {
3853 destVolume = cache.m_recallTrackingVolume;
3854 destinationSearchType = "recall";
3855 // the recal case ----------
3857 } else if (!destVolume) {
3858 // (3) GLOBAL SEARCH
3859 destinationSearchType = "global search";
3861 // if the propagation has not been done already (for direction estimation)
3862 // do the global search always with a reference propagation
3863 if (!refParameters && associatedVolume) {
3864 refParameters = cache.m_ownedPtrs.push(prop.propagateParameters(
3865 ctx, *parm, sf, dir, false, m_fieldProperties, particle, false,
3866 associatedVolume));
3867 }
3868 // get the destination Volume
3869 if (refParameters) {
3870 destVolume = cache.volume(ctx,refParameters->position());
3871 }
3872 // ------ the last chance : associate to the globalReferencePoint
3873 // std::cout << "destVolume: " << destVolume << " ref par: " << refParameters << "
3874 // associatedVolume: "
3875 // << associatedVolume << std::endl;
3876 if (!destVolume) {
3877 destVolume = cache.volume(ctx,sf.globalReferencePoint());
3878 }
3879 }
3880 ATH_MSG_VERBOSE(" [I] Destination Information gathered through : " << destinationSearchType
3881 << ".");
3882 }
3883 // screen output summary -----------------------------------------------------------
3884 if (msgLvl(MSG::VERBOSE)) {
3885 ATH_MSG_VERBOSE(" [+] Association Volume search ...... "
3886 << (associatedVolume ? "ok." : "failed."));
3887 ATH_MSG_VERBOSE(" [+] Association Layer search ...... "
3888 << (associatedLayer ? "ok." : "failed."));
3889 ATH_MSG_VERBOSE(" [+] Destinaiton Volume search ...... " << (destVolume ? "ok." : "failed."));
3890 // give a line of output when start volume is destination volume
3891 if (destVolume == associatedVolume) {
3892 ATH_MSG_VERBOSE(" [+] Start volume is destination volume.");
3893 }
3894 const std::string navDirString =
3895 ((navigationDirection < 0) ? "oppositeMomentum"
3896 : (navigationDirection > 0) ? "alongMomentum" : "undefined");
3897 ATH_MSG_VERBOSE(" [+] NavigationDirection is : " << navDirString);
3898 ATH_MSG_VERBOSE(" [I] initializeNaviagtion() end ---------------------- ");
3899 }
3900
3901 // ----------------------------------------------------------------------------
3902 return navigationDirection;
3903}
3904
3905bool
3907 const IPropagator& prop,
3908 const TrackParameters& startParm,
3909 const TrackParameters& parsOnLayer,
3910 const TrackingVolume& tvol,
3911 PropDirection dir,
3912 ParticleHypothesis particle) const
3913{
3914
3915 const Amg::Vector3D& startPosition = startParm.position();
3916 const Amg::Vector3D& onLayerPosition = parsOnLayer.position();
3917
3918 // the 3D distance to the layer intersection
3919 const double distToLayer = (startPosition - onLayerPosition).mag();
3920 // get the innermost contained surface for crosscheck
3921 const auto& boundarySurfaces = tvol.boundarySurfaces();
3922
3923 // only for tubes the crossing makes sense to check for validity
3924 if (boundarySurfaces.size() == 4) {
3925 // it can be either the next layer from the initial point, or the inner tube boundary surface
3926 const Trk::Surface& insideSurface =
3927 (boundarySurfaces[Trk::tubeInnerCover])->surfaceRepresentation();
3928 // const Trk::TrackParameters* parsOnInsideSurface =
3929 std::unique_ptr<const Trk::TrackParameters> const parsOnInsideSurface(prop.propagateParameters(
3930 ctx, startParm, insideSurface, dir, true, m_fieldProperties, particle));
3931
3932 const double distToInsideSurface =
3933 parsOnInsideSurface ? (startPosition - (parsOnInsideSurface->position())).mag() : 10e10;
3934
3935 ATH_MSG_VERBOSE(" [+] Radial direction check start - at " << positionOutput(startPosition));
3936 ATH_MSG_VERBOSE(" [+] Radial direction check layer - at " << positionOutput(onLayerPosition));
3937 if (parsOnInsideSurface) {
3938 ATH_MSG_VERBOSE(" [+] Radial direction check inner - at "
3939 << positionOutput(parsOnInsideSurface->position()));
3940 }
3941
3942 // memory cleanup (no garbage bin, this is faster)
3943 ATH_MSG_VERBOSE(" [+] Check radial direction: distance layer / boundary = "
3944 << distToLayer << " / " << distToInsideSurface);
3945 // the intersection with the original layer is valid if it is before the inside surface
3946 return distToLayer < distToInsideSurface;
3947 }
3948 return true;
3949}
3950
3951std::string
3953{
3954 std::stringstream outStream;
3955
3956 if (m_printRzOutput) {
3957 outStream << "[r,phi,z] = [ " << pos.perp() << ", " << pos.phi() << ", " << pos.z() << " ]";
3958 } else {
3959 outStream << "[xyz] = [ " << pos.x() << ", " << pos.y() << ", " << pos.z() << " ]";
3960 }
3961 return outStream.str();
3962}
3963
3964void
3966 Cache& cache,
3967 const Trk::IPropagator& prop,
3969 const Trk::Layer& lay,
3970 const Trk::TrackingVolume& /*tvol*/,
3971 Trk::PropDirection propDir,
3972 Trk::ParticleHypothesis particle) const
3973{
3974
3975 ATH_MSG_VERBOSE(" [+] addMaterialEffectsOnTrack() - at " << positionOutput(parms->position()));
3976 // preparation for the material effects on track
3977 const Trk::MaterialProperties* materialProperties = nullptr;
3978 double pathCorrection = 0.;
3980 // make sure the parameters are on surface
3981 if (parms->associatedSurface() != lay.surfaceRepresentation()) {
3982 parsOnLayer = cache.m_ownedPtrs.push(
3983 prop.propagateParameters(ctx, *parms, lay.surfaceRepresentation(),
3985 } else {
3986 parsOnLayer = parms;
3987 }
3988 // should not really happen
3989 if (!parsOnLayer) {
3990 return;
3991 }
3992 // reference material section:
3993 pathCorrection = pathCorrection > 0. ? pathCorrection
3995 parsOnLayer->position(), parsOnLayer->momentum());
3996
3997 // material properties are not given by the reference material, get them from the layer
3998 if (!materialProperties) {
3999 materialProperties = lay.fullUpdateMaterialProperties(*parsOnLayer);
4000 }
4001
4002 if (!materialProperties) {
4003 ATH_MSG_DEBUG(" [!] No MaterialProperties on Layer after intersection.");
4004 return;
4005 }
4006 // pure validation mode
4007 if (!cache.m_matstates) {
4008 if (cache.m_extrapolationCache) {
4009 const double tInX0 = pathCorrection * materialProperties->thicknessInX0();
4010 if (m_dumpCache) {
4011 ATH_MSG_DEBUG(cache.to_string(" addMaterialEffectsOnTrack"));
4012 }
4013 cache.m_extrapolationCache->updateX0(tInX0);
4014 const double currentQoP = parsOnLayer->parameters()[Trk::qOverP];
4015 const Trk::EnergyLoss energyLoss(m_elossupdater->energyLoss(
4016 *materialProperties, std::abs(1. / currentQoP), pathCorrection, propDir, particle));
4017 cache.m_extrapolationCache->updateEloss(energyLoss.meanIoni(),
4018 energyLoss.sigmaIoni(),
4019 energyLoss.meanRad(),
4020 energyLoss.sigmaRad());
4021 if (m_dumpCache) {
4022 ATH_MSG_DEBUG(cache.to_string(" After"));
4023 }
4024 }
4025 ATH_MSG_VERBOSE(" [V] Validation mode: MaterialProperties found on this layer.");
4026 } else { // collection mode
4027 // material properties from the layer
4028 const double tInX0 = pathCorrection * materialProperties->thicknessInX0();
4029 // get the q/p for the energyLoss object
4030 const double currentQoP = parsOnLayer->parameters()[Trk::qOverP];
4031 auto energyLoss = m_elossupdater->energyLoss(
4032 *materialProperties, std::abs(1. / currentQoP), pathCorrection, propDir,
4033 particle);
4034 // get the scattering angle
4035 const double sigmaMS = std::sqrt(m_msupdater->sigmaSquare(
4036 *materialProperties, std::abs(1. / currentQoP), pathCorrection, particle));
4037 auto scatAngles =
4038 ScatteringAngles(0, 0, sigmaMS / std::sin(parsOnLayer->parameters()[Trk::theta]), sigmaMS);
4039
4040 // update cache
4041 if (cache.m_extrapolationCache) {
4042 if (energyLoss.meanIoni() == 0. && tInX0 > 0.) {
4043 ATH_MSG_WARNING(" Extrapolator: the ExtrapolationCache cannot work "
4044 "because the ElossUpdator is wrongly configured: "
4045 "switch joboption DetailedEloss on ");
4046 }
4047 if (m_dumpCache) {
4048 ATH_MSG_DEBUG(cache.to_string(" addMaterialEffectsOnTrack"));
4049 }
4050 cache.m_extrapolationCache->updateX0(tInX0);
4051 cache.m_extrapolationCache->updateEloss(energyLoss.meanIoni(),
4052 energyLoss.sigmaIoni(),
4053 energyLoss.meanRad(),
4054 energyLoss.sigmaRad());
4055 if (m_dumpCache) {
4056 ATH_MSG_DEBUG(cache.to_string(" After"));
4057 }
4058 }
4059 auto meot = std::make_unique<Trk::MaterialEffectsOnTrack>(
4060 tInX0, scatAngles, std::make_unique<Trk::EnergyLoss>(std::move(energyLoss)),
4062 // push it to the material states
4063 cache.m_matstates->push_back(new TrackStateOnSurface(
4064 nullptr, cache.m_ownedPtrs.move(parsOnLayer), std::move(meot)));
4065 }
4066}
4067
4068
4071 Cache& cache,
4073 double pathLim,
4075 Trk::ParticleHypothesis particle,
4076 const Trk::TrackingVolume* destVol,
4077 MaterialUpdateMode matupmod) const
4078{
4079 // returns:
4080 // A) curvilinear track parameters if path limit reached
4081 // B) boundary parameters (at destination volume boundary)
4082 // initialize the return parameters vector
4084 const Trk::TrackingVolume* currVol = nullptr;
4085 const Trk::TrackingVolume* nextVol = nullptr;
4086 const Trk::TrackingVolume* assocVol = nullptr;
4087 unsigned int iDest = 0;
4088
4089 // set tracking geometry in cache
4090 cache.setTrackingGeometry(*m_navigator, ctx);
4091 // destination volume boundary ?
4092 if (destVol && m_navigator->atVolumeBoundary(currPar, destVol, dir, nextVol, m_tolerance) &&
4093 nextVol != destVol) {
4094 pathLim = cache.m_path;
4095 return currPar;
4096 }
4097
4098 const bool resolveActive = true;
4099 if (!cache.m_highestVolume) {
4101 }
4102
4103 // navigation surfaces
4104 if (cache.m_navigSurfs.capacity() > m_maxNavigSurf) {
4105 cache.m_navigSurfs.reserve(m_maxNavigSurf);
4106 }
4107 cache.m_navigSurfs.clear();
4108
4109 // target volume may not be part of tracking geometry
4110 if (destVol) {
4111 const Trk::TrackingVolume* tgVol =
4112 cache.m_trackingGeometry->trackingVolume(destVol->volumeName());
4113 if (!tgVol || tgVol != destVol) {
4114 const auto& bounds = destVol->boundarySurfaces();
4115 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
4116 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
4117 cache.m_navigSurfs.emplace_back(&surf, true);
4118 }
4119 iDest = bounds.size();
4120 }
4121 }
4122
4123 // resolve current position
4124 bool updateStatic = false;
4125 Amg::Vector3D gp = parm->position();
4126 if (!cache.m_currentStatic || !cache.m_currentStatic->inside(gp, m_tolerance)) {
4128 updateStatic = true;
4129 }
4130
4131 // the navigation sequence may have been evaluated already - check the cache
4132
4133 bool navigDone = false;
4135 if ((cache.m_parametersAtBoundary.nextParameters->position() - currPar->position()).mag() <
4136 0.001 &&
4137 cache.m_parametersAtBoundary.nextParameters->momentum().dot(currPar->momentum()) > 0.001) {
4138 nextVol = cache.m_parametersAtBoundary.nextVolume;
4139 navigDone = true;
4140 if (nextVol != cache.m_currentStatic) {
4141 cache.m_currentStatic = nextVol;
4142 updateStatic = true;
4143 }
4144 }
4145 }
4146
4147 if (!navigDone &&
4148 m_navigator->atVolumeBoundary(
4149 currPar, cache.m_currentStatic, dir, nextVol, m_tolerance) &&
4150 nextVol != cache.m_currentStatic) {
4151 // no next volume found --- end of the world
4152 if (!nextVol) {
4153 ATH_MSG_DEBUG(" [+] Word boundary reached - at "
4154 << positionOutput(currPar->position()));
4155 if (!destVol) {
4156 pathLim = cache.m_path;
4157 }
4158 return currPar;
4159 }
4160 cache.m_currentStatic = nextVol;
4161 updateStatic = true;
4162 }
4163
4164 // alignable volume ?
4166 if (cache.m_currentStatic->isAlignable()) {
4167 const Trk::AlignableTrackingVolume* alignTV =
4168 static_cast<const Trk::AlignableTrackingVolume*>(cache.m_currentStatic);
4170 ctx, cache, *m_stepPropagator, currPar, nullptr, alignTV, dir, particle));
4171 if (nextPar) {
4173 ctx, cache, nextPar, pathLim, dir, particle, destVol, matupmod);
4174 }
4175 return {};
4176
4177 }
4178 }
4179
4180 // update if new static volume
4181 if (updateStatic) { // retrieve boundaries
4182 cache.retrieveBoundaries();
4183 //
4184 cache.m_detachedVols.clear();
4185 cache.m_detachedBoundaries.clear();
4186 cache.m_denseVols.clear();
4187 cache.m_denseBoundaries.clear();
4188 cache.m_layers.clear();
4189 cache.m_navigLays.clear();
4190
4191 // detached volume boundaries
4194 if (!detVols.empty()) {
4195 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const>::iterator iTer = detVols.begin();
4196 for (; iTer != detVols.end(); ++iTer) {
4197 // active station ?
4198 const Trk::Layer* layR = (*iTer)->layerRepresentation();
4199 const bool active = layR && layR->layerType();
4200 const auto& detBounds = (*iTer)->trackingVolume()->boundarySurfaces();
4201 if (active) {
4202 cache.m_detachedVols.emplace_back(*iTer, detBounds.size());
4203 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
4204 const Trk::Surface& surf = (detBounds[ibb])->surfaceRepresentation();
4205 cache.m_detachedBoundaries.emplace_back(&surf, true);
4206 }
4207 } else if (cache.m_currentStatic->geometrySignature() != Trk::MS ||
4209 (*iTer)->name().compare((*iTer)->name().size() - 4, 4, "PERM") ==
4210 0) {
4211 // retrieve inert detached
4212 // objects only if needed
4213 if ((*iTer)->trackingVolume()->zOverAtimesRho() != 0. &&
4214 ((*iTer)->trackingVolume()->confinedDenseVolumes().empty()) &&
4215 ((*iTer)->trackingVolume()->confinedArbitraryLayers().empty())) {
4216 cache.m_denseVols.emplace_back((*iTer)->trackingVolume(), detBounds.size());
4217 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
4218 const Trk::Surface& surf = (detBounds[ibb])->surfaceRepresentation();
4219 cache.m_denseBoundaries.emplace_back(&surf, true);
4220 }
4221 }
4223 (*iTer)->trackingVolume()->confinedArbitraryLayers();
4224 if (!(*iTer)->trackingVolume()->confinedDenseVolumes().empty() ||
4225 (confLays.size() > detBounds.size())) {
4226 cache.m_detachedVols.emplace_back(*iTer, detBounds.size());
4227 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
4228 const Trk::Surface& surf = (detBounds[ibb])->surfaceRepresentation();
4229 cache.m_detachedBoundaries.emplace_back(&surf, true);
4230 }
4231 } else if (!confLays.empty()) {
4232 for (const Trk::Layer* const lIt : confLays) {
4233 cache.addOneNavigationLayer((*iTer)->trackingVolume(), lIt);
4234 }
4235 }
4236 }
4237 }
4238 }
4239 cache.m_denseResolved = std::pair<unsigned int, unsigned int>(cache.m_denseVols.size(),
4240 cache.m_denseBoundaries.size());
4241 cache.m_layerResolved = cache.m_layers.size();
4242 }
4243
4244 cache.m_navigSurfs.insert(
4245 cache.m_navigSurfs.end(), cache.m_staticBoundaries.begin(), cache.m_staticBoundaries.end());
4246
4247 // resolve the use of dense volumes
4248 cache.m_dense =
4251
4252 // reset remaining counters
4253 cache.m_currentDense = cache.m_dense ? cache.m_currentStatic : cache.m_highestVolume;
4254 cache.m_navigBoundaries.clear();
4255 if (cache.m_denseVols.size() > cache.m_denseResolved.first) {
4256 cache.m_denseVols.resize(cache.m_denseResolved.first);
4257 }
4258 while (cache.m_denseBoundaries.size() > cache.m_denseResolved.second) {
4259 cache.m_denseBoundaries.pop_back();
4260 }
4261
4262 if (cache.m_layers.size() > cache.m_layerResolved) {
4263 cache.m_navigLays.resize(cache.m_layerResolved);
4264 }
4265 while (cache.m_layers.size() > cache.m_layerResolved) {
4266 cache.m_layers.pop_back();
4267 }
4268
4269 // current detached volumes
4270 // collect : subvolume boundaries, ordered/unordered layers, confined dense volumes
4272 // const Trk::DetachedTrackingVolume* currentActive = 0;
4273 std::vector<std::pair<const Trk::TrackingVolume*, unsigned int>> navigVols;
4274
4275 gp = currPar->position();
4276 std::vector<const Trk::DetachedTrackingVolume*> detVols =
4278 std::vector<const Trk::DetachedTrackingVolume*>::iterator dIter = detVols.begin();
4279 for (; dIter != detVols.end(); ++dIter) {
4280 const Trk::Layer* layR = (*dIter)->layerRepresentation();
4281 const bool active = layR && layR->layerType();
4282 if (active && !resolveActive) {
4283 continue;
4284 }
4286 (*dIter)->name().compare((*dIter)->name().size() - 4, 4, "PERM") != 0) {
4287 continue;
4288 }
4289 const Trk::TrackingVolume* dVol = (*dIter)->trackingVolume();
4290 // detached volume exit ?
4291 const bool dExit =
4292 m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) && !nextVol;
4293 if (dExit) {
4294 continue;
4295 }
4296 // inert material
4297 const auto confinedDense = dVol->confinedDenseVolumes();
4298 const auto confinedLays = dVol->confinedArbitraryLayers();
4299
4300 if (!active && confinedDense.empty() && confinedLays.empty()) {
4301 continue;
4302 }
4303 const auto& bounds = dVol->boundarySurfaces();
4304 if (!active && confinedDense.empty() && confinedLays.size() <= bounds.size()) {
4305 continue;
4306 }
4307 if (!confinedDense.empty() || !confinedLays.empty()) {
4308 navigVols.emplace_back(dVol, bounds.size());
4309 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
4310 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
4311 cache.m_navigBoundaries.emplace_back(&surf, true);
4312 }
4313 // collect dense volume boundary
4314 if (!confinedDense.empty()) {
4315 auto vIter = confinedDense.begin();
4316 for (; vIter != confinedDense.end(); ++vIter) {
4317 const auto& bounds = (*vIter)->boundarySurfaces();
4318 cache.m_denseVols.emplace_back(*vIter, bounds.size());
4319 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
4320 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
4321 cache.m_denseBoundaries.emplace_back(&surf, true);
4322 }
4323 }
4324 }
4325 // collect unordered layers
4326 if (!confinedLays.empty()) {
4327 for (const auto *confinedLay : confinedLays) {
4328 cache.addOneNavigationLayer(dVol, confinedLay);
4329 }
4330 }
4331 } else { // active material
4332 const Trk::TrackingVolume* detVol = dVol->associatedSubVolume(gp);
4333 if (!detVol && dVol->confinedVolumes()) {
4334 std::span<Trk::TrackingVolume const * const> const subvols = dVol->confinedVolumes()->arrayObjects();
4335 for (const auto *subvol : subvols) {
4336 if (subvol->inside(gp, m_tolerance)) {
4337 detVol = subvol;
4338 break;
4339 }
4340 }
4341 }
4342
4343 if (!detVol) {
4344 detVol = dVol;
4345 }
4346 bool vExit =
4347 m_navigator->atVolumeBoundary(currPar, detVol, dir, nextVol, m_tolerance) &&
4348 nextVol != detVol;
4349 if (vExit && nextVol && nextVol->inside(gp, m_tolerance)) {
4350 detVol = nextVol;
4351 vExit = false;
4352 }
4353 if (!vExit) {
4354 const auto& bounds = detVol->boundarySurfaces();
4355 navigVols.emplace_back(detVol, bounds.size());
4356 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
4357 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
4358 cache.m_navigBoundaries.emplace_back(&surf, true);
4359 }
4360 if (detVol->zOverAtimesRho() != 0.) {
4361 cache.m_denseVols.emplace_back(detVol, bounds.size());
4362 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
4363 const Trk::Surface& surf = (bounds[ib])->surfaceRepresentation();
4364 cache.m_denseBoundaries.emplace_back(&surf, true);
4365 }
4366 }
4367 // layers ?
4368 if (detVol->confinedLayers()) {
4369 std::span<Trk::Layer const* const> const cLays = detVol->confinedLayers()->arrayObjects();
4370 for (const auto* cLay : cLays) {
4371 if (cLay->layerType() > 0 || cLay->layerMaterialProperties()) {
4372 cache.addOneNavigationLayer(cLay);
4373 }
4374 }
4375 } else if (!detVol->confinedArbitraryLayers().empty()) {
4376 for (const auto & pThisLayer: detVol->confinedArbitraryLayers()) {
4377 cache.addOneNavigationLayer(detVol, pThisLayer);
4378 }
4379 }
4380 }
4381 }
4382 }
4383
4384 // confined layers
4385 if (cache.m_currentStatic->confinedLayers() && updateStatic) {
4386 // if ( cache.m_currentStatic->confinedLayers() ) {
4387 std::span<Trk::Layer const* const> const cLays = cache.m_currentStatic->confinedLayers()->arrayObjects();
4388 for (const auto* cLay : cLays) {
4389 if (cLay->layerType() > 0 || cLay->layerMaterialProperties()) {
4390 cache.addOneNavigationLayer(cLay);
4391 }
4392 }
4393 }
4395
4396 // current dense
4397 cache.m_currentDense = cache.m_highestVolume;
4398 if (cache.m_dense && cache.m_denseVols.empty()) {
4399 cache.m_currentDense = cache.m_currentStatic;
4400 } else {
4401 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
4402 const Trk::TrackingVolume* dVol = cache.m_denseVols[i].first;
4403 if (dVol->inside(currPar->position(), m_tolerance) && dVol->zOverAtimesRho() != 0.) {
4404 if (!m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) ||
4405 nextVol == dVol) {
4406 cache.m_currentDense = dVol;
4407 }
4408 }
4409 }
4410 }
4411
4412 // ready to propagate
4413 // till: A/ static volume boundary(bcheck=true) , B/ material
4414 // layer(bcheck=true), C/ destination surface(bcheck=false) update of
4415 // cache.m_navigSurfs required if I/ entry into new navig volume, II/ exit
4416 // from currentActive without overlaps
4417 nextVol = nullptr;
4418 while (currPar) {
4419 double path = 0.;
4420 if (pathLim > 0.) {
4421 path = pathLim;
4422 }
4423 std::vector<unsigned int> solutions;
4424 ATH_MSG_DEBUG(" [+] Starting propagation at position "
4425 << positionOutput(currPar->position())
4426 << " (current momentum: " << currPar->momentum().mag() << ")");
4427 ATH_MSG_DEBUG(" [+] " << cache.m_navigSurfs.size() << " target surfaces in '"
4428 << cache.m_currentDense->volumeName()
4429 << "'."); // verify that material input makes sense
4430 ATH_MSG_DEBUG(" [+] "
4431 << " with path limit" << pathLim
4432 << ","); // verify that material input makes sense
4433 ATH_MSG_DEBUG(" [+] "
4434 << " in the direction" << dir << "."); // verify that material input makes sense
4435 if (!(cache.m_currentDense->inside(currPar->position(), m_tolerance) ||
4436 m_navigator->atVolumeBoundary(
4437 currPar, cache.m_currentDense, dir, assocVol, m_tolerance))) {
4438 cache.m_currentDense = cache.m_highestVolume;
4439 }
4441 ctx, *currPar, cache.m_navigSurfs, dir, m_fieldProperties, particle,
4442 solutions, path, true, false, cache.m_currentDense));
4443 if (nextPar) {
4444 ++cache.m_nPropagations;
4445 ATH_MSG_DEBUG(" [+] Position after propagation - at "
4446 << positionOutput(nextPar->position()));
4447 ATH_MSG_DEBUG(" [+] Momentum after propagation - " << nextPar->momentum());
4448 }
4449
4450 if (pathLim > 0. && cache.m_path + path >= pathLim) {
4451 cache.m_path += path;
4452 return nextPar;
4453 }
4454 // check missing volume boundary
4455 if (nextPar && !(cache.m_currentDense->inside(nextPar->position(), m_tolerance) ||
4456 m_navigator->atVolumeBoundary(
4457 nextPar, cache.m_currentDense, dir, assocVol, m_tolerance))) {
4458 ATH_MSG_DEBUG(" [!] ERROR: missing volume boundary for volume"
4459 << cache.m_currentDense->volumeName());
4460 if (cache.m_currentDense->zOverAtimesRho() != 0.) {
4461 ATH_MSG_DEBUG(" [!] ERROR: trying to recover: repeat the propagation step in"
4462 << cache.m_highestVolume->volumeName());
4463 cache.m_currentDense = cache.m_highestVolume;
4464 continue;
4465 }
4466 }
4467 if (!nextPar) {
4468 ATH_MSG_DEBUG(" [!] Propagation failed, return 0");
4469 cache.m_parametersAtBoundary.boundaryInformation(cache.m_currentStatic, nextPar, nextPar);
4470 // @TODO reset m_parametersAtBoundary ?
4471 return {};
4472 }
4473 cache.m_path += path;
4474 if (pathLim > 0.) {
4475 pathLim -= path;
4476 }
4477 ATH_MSG_DEBUG(" [+] Number of intersection solutions: " << solutions.size());
4478 // Material effects
4479 if (cache.m_currentDense->zOverAtimesRho() != 0.&&
4480 cache.m_extrapolationCache) {
4481 const double dInX0 = std::abs(path) / cache.m_currentDense->x0();
4482 const double currentqoverp = nextPar->parameters()[Trk::qOverP];
4483 const MaterialProperties materialProperties(*cache.m_currentDense, std::abs(path));
4484 const EnergyLoss eloss = (m_elossupdater->energyLoss(
4485 materialProperties, std::abs(1. / currentqoverp), 1., dir, particle));
4486 if (m_dumpCache) {
4487 ATH_MSG_DEBUG(cache.to_string( " extrapolateToVolumeWithPathLimit"));
4488 }
4489 cache.m_extrapolationCache->updateX0(dInX0);
4491 eloss.meanIoni(), eloss.sigmaIoni(), eloss.meanRad(), eloss.sigmaRad());
4492 if (m_dumpCache) {
4493 ATH_MSG_DEBUG(cache.to_string(" After"));
4494 }
4495 }
4496
4497 unsigned int iSol = 0;
4498 while (iSol < solutions.size()) {
4499 if (solutions[iSol] < iDest) {
4500 return nextPar;
4501 } if (solutions[iSol] < iDest + cache.m_staticBoundaries.size()) {
4502 // material attached ?
4503 const Trk::Layer* mb = cache.m_navigSurfs[solutions[iSol]].first->materialLayer();
4504 if (mb) {
4505 if (mb->layerMaterialProperties() &&
4506 mb->layerMaterialProperties()->fullMaterial(nextPar->position())) {
4507 const double pIn = nextPar->momentum().mag();
4508 const IMaterialEffectsUpdator* currentUpdator =
4510 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
4512 if (currentUpdator) {
4513 nextPar = cache.m_ownedPtrs.push(
4514 currentUpdator->update(
4515 currentUpdatorCache, nextPar, *mb, dir, particle, matupmod));
4516 }
4517 if (!nextPar) {
4518 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
4520 return {};
4521 } // the MEOT will be saved at the end
4522 ATH_MSG_VERBOSE(" Updated energy loss:" << nextPar->momentum().mag() - pIn
4523 << "at position:" << nextPar->position());
4524
4525 }
4526 }
4527 // static volume boundary; return to the main loop
4528 const unsigned int index = solutions[iSol] - iDest;
4529 // use global coordinates to retrieve attached volume (just for static!)
4530 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
4531 nextPar->position(), nextPar->momentum(), dir);
4532 if (nextVol != cache.m_currentStatic) {
4533 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
4534 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '"
4535 << cache.m_currentStatic->volumeName()
4536 << "', geoID: " << cache.m_currentStatic->geometrySignature());
4537
4538 if (m_navigator->atVolumeBoundary(
4539 nextPar, cache.m_currentStatic, dir, assocVol, m_tolerance) &&
4540 assocVol != cache.m_currentStatic) {
4541 cache.m_currentDense = cache.m_dense ? nextVol : cache.m_highestVolume;
4542 }
4543 // no next volume found --- end of the world
4544 if (!nextVol) {
4545 ATH_MSG_DEBUG(" [+] World boundary reached - at "
4546 << positionOutput(nextPar->position()));
4547 if (!destVol) {
4548 pathLim = cache.m_path;
4549 return nextPar;
4550 }
4551 }
4552 // next volume found and parameters are at boundary
4553 if (nextVol /*&& nextPar nextPar is dereferenced after*/) {
4554 ATH_MSG_DEBUG(" [+] Crossing to next volume '"
4555 << nextVol->volumeName()
4556 << "', next geoID: " << nextVol->geometrySignature());
4557 ATH_MSG_DEBUG(" [+] Crossing position is - at "
4558 << positionOutput(nextPar->position()));
4559 if (!destVol &&
4560 cache.m_currentStatic->geometrySignature() != nextVol->geometrySignature()) {
4561 pathLim = cache.m_path;
4562 return nextPar;
4563 }
4564 }
4566 ctx, cache, nextPar, pathLim, dir, particle, destVol, matupmod);
4567 }
4568 } else if (solutions[iSol] <
4569 iDest + cache.m_staticBoundaries.size() + cache.m_layers.size()) {
4570 // next layer; don't return passive material layers unless required
4571 const unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size();
4572 const Trk::Layer* nextLayer = cache.m_navigLays[index].second;
4573 // material update ?
4574 bool matUp = nextLayer->fullUpdateMaterialProperties(*nextPar) &&
4575 m_includeMaterialEffects && nextLayer->isOnLayer(nextPar->position());
4576
4577 // material update: pre-update
4578 const IMaterialEffectsUpdator* currentUpdator =
4580 IMaterialEffectsUpdator::ICache& currentUpdatorCache =
4582
4583 if (matUp && nextLayer->surfaceArray()) {
4584 const double pIn = nextPar->momentum().mag();
4585 if (currentUpdator) {
4586 nextPar = cache.m_ownedPtrs.push(
4587 currentUpdator->preUpdate(
4588 currentUpdatorCache, nextPar, *nextLayer, dir, particle, matupmod));
4589 }
4590 if (!nextPar) {
4591 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
4593 return {};
4594 } // the MEOT will be saved at the end
4595 ATH_MSG_VERBOSE(" Pre-update energy loss:"
4596 << nextPar->momentum().mag() - pIn << "at position:"
4597 << nextPar->position() << ", current momentum:" << nextPar->momentum());
4598
4599 }
4600 // active surface intersections ( Fatras hits ...)
4601 if (cache.m_parametersOnDetElements && particle != Trk::neutron) {
4602 if (nextLayer->surfaceArray()) {
4603 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on layer.");
4604 overlapSearch(ctx, cache, *m_subPropagators[0], currPar, nextPar,
4605 *nextLayer, *cache.m_currentStatic, dir, true,
4606 particle);
4607 } else if (nextLayer->layerType() > 0 &&
4608 nextLayer->isOnLayer(nextPar->position())) {
4609 ATH_MSG_VERBOSE(" [o] Collecting intersection with active layer.");
4610 cache.m_parametersOnDetElements->emplace_back(nextPar->uniqueClone());
4611 }
4612 } // -------------------------- Fatras mode off -----------------------------------
4613
4614 if (matUp) {
4615 if (nextLayer->surfaceArray()) {
4616 // verify there is material for postUpdate
4617 const double postFactor = nextLayer->postUpdateMaterialFactor(*nextPar, dir);
4618 if (postFactor > 0.1) {
4619 const double pIn = nextPar->momentum().mag();
4620 if (currentUpdator) {
4621 nextPar = cache.m_ownedPtrs.push(currentUpdator->postUpdate(
4622 currentUpdatorCache, *nextPar, *nextLayer, dir, particle,
4623 matupmod));
4624 }
4625 if (!nextPar) {
4626 ATH_MSG_VERBOSE("postUpdate failed");
4627 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
4629 return {};
4630 } // the MEOT will be saved at the end
4631 ATH_MSG_VERBOSE(" Post-update energy loss:" << nextPar->momentum().mag() - pIn
4632 << "at position:"
4633 << nextPar->position());
4634
4635 }
4636 } else {
4637 const double pIn = nextPar->momentum().mag();
4638 if (currentUpdator) {
4639 nextPar = cache.m_ownedPtrs.push(
4640 currentUpdator->update(currentUpdatorCache, nextPar,
4641 *nextLayer, dir, particle, matupmod));
4642 }
4643 if (!nextPar) {
4644 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
4646 return {};
4647 } // the MEOT will be saved at the end
4648 ATH_MSG_VERBOSE(" Update energy loss:" << nextPar->momentum().mag() - pIn
4649 << "at position:" << nextPar->position());
4650
4651 }
4652 }
4653 currPar = nextPar;
4654 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() +
4655 cache.m_denseBoundaries.size()) {
4656 // dense volume boundary
4657 unsigned int index =
4658 solutions[iSol] - iDest - cache.m_staticBoundaries.size() - cache.m_layers.size();
4659 std::vector<std::pair<const Trk::TrackingVolume*, unsigned int>>::iterator dIter =
4660 cache.m_denseVols.begin();
4661 while (dIter != cache.m_denseVols.end() && index >= (*dIter).second) {
4662 index -= (*dIter).second;
4663 ++dIter;
4664 }
4665 if (dIter != cache.m_denseVols.end()) {
4666 currVol = (*dIter).first;
4667 nextVol =
4668 ((*dIter).first->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
4669 // the boundary orientation is not reliable
4670 const Amg::Vector3D tp =
4671 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
4672 if (currVol->inside(tp, 0.)) {
4673 cache.m_currentDense = currVol;
4674 } else if (!nextVol || !nextVol->inside(tp, 0.)) { // search for dense volumes
4675 cache.m_currentDense = cache.m_highestVolume;
4676 if (cache.m_dense && cache.m_denseVols.empty()) {
4677 cache.m_currentDense = cache.m_currentStatic;
4678 } else {
4679 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
4680 const Trk::TrackingVolume* dVol = cache.m_denseVols[i].first;
4681 if (dVol->inside(tp, 0.) && dVol->zOverAtimesRho() != 0.) {
4682 cache.m_currentDense = dVol;
4683 ATH_MSG_DEBUG(" [+] Next dense volume found: '"
4684 << cache.m_currentDense->volumeName() << "'.");
4685 break;
4686 }
4687 } // loop over dense volumes
4688 }
4689 } else {
4690 cache.m_currentDense = nextVol;
4691 ATH_MSG_DEBUG(" [+] Next dense volume: '" << cache.m_currentDense->volumeName()
4692 << "'.");
4693 }
4694 }
4695 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() +
4696 cache.m_denseBoundaries.size() +
4697 cache.m_navigBoundaries.size()) {
4698 // navig volume boundary
4699 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() -
4700 cache.m_layers.size() - cache.m_denseBoundaries.size();
4701 std::vector<std::pair<const Trk::TrackingVolume*, unsigned int>>::iterator nIter =
4702 navigVols.begin();
4703 while (nIter != navigVols.end() && index >= (*nIter).second) {
4704 index -= (*nIter).second;
4705 ++nIter;
4706 }
4707 if (nIter != navigVols.end()) {
4708 currVol = (*nIter).first;
4709 nextVol =
4710 ((*nIter).first->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
4711 // the boundary orientation is not reliable
4712 const Amg::Vector3D tp =
4713 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
4714 if (nextVol && nextVol->inside(tp, 0.)) {
4715 ATH_MSG_DEBUG(" [+] Navigation volume boundary, entering volume '"
4716 << nextVol->volumeName() << "'.");
4717 } else if (currVol->inside(tp, 0.)) {
4718 nextVol = currVol;
4719 ATH_MSG_DEBUG(" [+] Navigation volume boundary, entering volume '"
4720 << nextVol->volumeName() << "'.");
4721 } else {
4722 nextVol = nullptr;
4723 ATH_MSG_DEBUG(" [+] Navigation volume boundary, leaving volume '"
4724 << currVol->volumeName() << "'.");
4725 }
4726 // return only if detached volume boundaries not collected
4727 // if ( nextVol || !detachedBoundariesIncluded )
4728 if (nextVol) {
4730 ctx, cache, nextPar, pathLim, dir, particle, destVol, matupmod);
4731 }
4732 currPar = nextPar;
4733 }
4734 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() +
4735 cache.m_denseBoundaries.size() +
4736 cache.m_navigBoundaries.size() +
4737 cache.m_detachedBoundaries.size()) {
4738 // detached volume boundary
4739 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() -
4740 cache.m_layers.size() - cache.m_denseBoundaries.size() -
4741 cache.m_navigBoundaries.size();
4742 std::vector<std::pair<const Trk::DetachedTrackingVolume*, unsigned int>>::iterator dIter =
4743 cache.m_detachedVols.begin();
4744 while (dIter != cache.m_detachedVols.end() && index >= (*dIter).second) {
4745 index -= (*dIter).second;
4746 ++dIter;
4747 }
4748 if (dIter != cache.m_detachedVols.end()) {
4749 currVol = (*dIter).first->trackingVolume();
4750 nextVol =
4751 ((*dIter).first->trackingVolume()->boundarySurfaces())[index]->attachedVolume(
4752 *nextPar, dir);
4753 // the boundary orientation is not reliable
4754 const Amg::Vector3D tp =
4755 nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
4756 if (nextVol && nextVol->inside(tp, 0.)) {
4757 ATH_MSG_DEBUG(" [+] Detached volume boundary, entering volume '"
4758 << nextVol->volumeName() << "'.");
4759 } else if (currVol->inside(tp, 0.)) {
4760 nextVol = currVol;
4761 ATH_MSG_DEBUG(" [+] Detached volume boundary, entering volume '"
4762 << nextVol->volumeName() << "'.");
4763 } else {
4764 nextVol = nullptr;
4765 ATH_MSG_DEBUG(" [+] Detached volume boundary, leaving volume '"
4766 << currVol->volumeName() << "'.");
4767 }
4768 // if ( nextVol || !detachedBoundariesIncluded)
4769 if (nextVol) {
4771 ctx, cache, nextPar, pathLim, dir, particle, destVol, matupmod);
4772 }
4773 currPar = nextPar;
4774 }
4775 }
4776 iSol++;
4777 }
4778 currPar = nextPar;
4779 }
4780 return {};
4781}
Scalar mag() const
mag method
#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)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
namespaced string utilities for TrkExTools
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Mixin class to perform additional checks on a component.
bool msgLvl(const MSG::Level lvl) const
Base Class for a navigation object (active) in the Calo realm.
const BinnedMaterial * binnedMaterial() const
access to binned material
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
for description of non-homogenous dense volumes
const IdentifiedMaterial * material(const Amg::Vector3D &position) const
access to material/id per bin
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
Access to distance solutions.
double second() const
Distance to second intersection solution along direction (for a cylinder surface)
int numberOfSolutions() const
Number of intersection solutions.
double absClosest() const
Absolute Distance to closest solution.
double toPointOfClosestApproach() const
Distance to point of closest approach along direction.
double first() const
Distance to first intersection solution along direction.
This class describes energy loss material effects in the ATLAS tracking EDM.
Definition EnergyLoss.h:34
double meanRad() const
double sigmaIoni() const
double meanIoni() const
double sigmaRad() const
double deltaE() const
returns the
void updateX0(double x0)
const EnergyLoss * eloss() const
double x0tot() const
void updateEloss(double ioni, double sigi, double rad, double sigr)
BooleanProperty m_stopWithUpdateZero
virtual std::unique_ptr< NeutralParameters > extrapolate(const NeutralParameters &parameters, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true) const override final
Main extrapolation Interface starting from neutral parameters and aiming at surface.
virtual std::unique_ptr< TrackParameters > extrapolateDirectly(const EventContext &ctx, const TrackParameters &parm, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion) const override final
Extrapolate directly: Forwards directly the call to the configured "Global" propagator.
BooleanProperty m_dumpCache
ToolHandle< IEnergyLossUpdator > m_elossupdater
ToolHandleArray< IPropagator > m_propagators
Private method for conversion of the synchronized geometry signature to the natural subdetector order...
void extrapolateToVolumeBoundary(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Layer *associatedLayer, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Private method for extrapolation in intermediate volume to boundary surface.
std::string positionOutput(const Amg::Vector3D &pos) const
For the output - global position.
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateToNextMaterialLayer(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Trk::Surface *destSurf, const Trk::TrackingVolume *vol, PropDirection dir, const BoundaryCheck &bcheck, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
BooleanProperty m_stopWithNavigationBreak
Gaudi::Accumulators::Counter m_navigationBreakOscillation
number of navigation breaks due to oscillation
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateWithinDetachedVolumes(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Surface &sf, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
C) call from extrapolateInsideVolume.
std::vector< std::pair< std::unique_ptr< Trk::TrackParameters >, int > > identifiedParameters_t
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateInAlignableTV(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Trk::Surface *destSurf, const Trk::AlignableTrackingVolume *vol, PropDirection dir, ParticleHypothesis particle=pion) const
void overlapSearch(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, Trk::CacheOwnedPtr< Trk::TrackParameters > parsOnLayer, const Layer &lay, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, bool startingLayer=false) const
Private to search for overlap surfaces.
std::unique_ptr< TrackParameters > extrapolateDirectlyImpl(const EventContext &ctx, const IPropagator &prop, const TrackParameters &parm, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion) const
Actual heavy lifting implementation for extrapolateDirectly.
UnsignedIntegerProperty m_initialLayerAttempts
Trk::TrackParametersUVector extrapolateBlindlyImpl(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, const Volume *boundaryVol=nullptr) const
Actual heavy lifting implementation for extrapolateBlindly.
Gaudi::Accumulators::Counter m_destinationThroughGlobalSearch
navigation intialization
BooleanProperty m_navigationBreakDetails
BooleanProperty m_resolveActive
Gaudi::Accumulators::Counter m_navigationBreakNoVolume
number of navigation breaks due no Volume found
Gaudi::Accumulators::Counter m_navigationBreakDistIncrease
number of navigation breaks due to distance increase
BooleanProperty m_skipInitialLayerUpdate
std::pair< Trk::CacheOwnedPtr< Trk::TrackParameters >, bool > extrapolateToIntermediateLayer(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Layer &lay, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise, bool perpendicularCheck=true) const
Private to extrapolate to the destination layer + surface, special treatment for exit layer.
ToolHandle< IMultipleScatteringUpdator > m_msupdater
Array of EnergyLoss updaters.
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateToVolumeWithPathLimit(const EventContext &ctx, Cache &cache, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, double pathLim, Trk::PropDirection dir, Trk::ParticleHypothesis particle, const Trk::TrackingVolume *destVol, MaterialUpdateMode matupmod=addNoise) const
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateFromLayerToLayer(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const TrackingVolume &tvol, const Layer *nextLayer, const Layer *destinationLayer, Trk::CacheOwnedPtr< Trk::TrackParameters > navParameters, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Private method to step from one to the last layer and stop at last layer (before 0) or before destina...
std::vector< const IMaterialEffectsUpdator * > m_subupdaters
static const unsigned int m_maxNavigVol
virtual std::unique_ptr< std::vector< std::pair< std::unique_ptr< Trk::TrackParameters >, int > > > collectIntersections(const EventContext &ctx, const Trk::TrackParameters &parm, Trk::PropDirection dir, Trk::ParticleHypothesis particle, int destination=3) const override final
Extrapolation method collecting intersections with subdetector boundaries and active volumes/layers.
virtual StatusCode finalize() override
AlgTool finalize method.
virtual std::unique_ptr< TrackParameters > extrapolateToVolume(const EventContext &ctx, const TrackParameters &parm, const Trk::TrackingVolume &vol, PropDirection dir=anyDirection, ParticleHypothesis particle=pion) const override final
Extrapolation to volume :
Gaudi::Accumulators::Counter m_extrapolateStepwiseCalls
number of calls: extrapolateStepwise() method
std::vector< const IPropagator * > m_subPropagators
< Propagators to chose from (steered by signature)
virtual std::vector< const TrackStateOnSurface * > * extrapolateM(const EventContext &ctx, const TrackParameters &parameters, const Surface &sf, PropDirection dir, const BoundaryCheck &bcheck, ParticleHypothesis particle=pion, Trk::ExtrapolationCache *cache=nullptr) const override final
Extrapolate to a destination surface, while collecting all the material layers in between.
virtual TrackParametersUVector extrapolateBlindly(const EventContext &ctx, const TrackParameters &parm, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, const Volume *boundaryVol=nullptr) const override final
extrapolateBlindly like step-wise extrapolation, but without a destination surface.
TrackParametersUVector extrapolateStepwiseImpl(const EventContext &ctx, const IPropagator &prop, const TrackParameters &parm, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion) const
DoubleProperty m_tolerance
BooleanProperty m_resolveMultilayers
number of sub valid propagators in the m_subPropagators array
unsigned int m_numOfValidPropagators
Gaudi::Accumulators::Counter m_extrapolateBlindlyCalls
number of calls: extrapolateBlindly() method
Gaudi::Accumulators::Counter m_overlapSurfaceHit
number of OverlapSurfaces found
virtual std::unique_ptr< TrackParameters > extrapolateTrack(const EventContext &ctx, const Track &trk, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise, Trk::ExtrapolationCache *cache=nullptr) const override final
Main extrapolation interface starting from a Trk::Track and aiming at Surface.
ToolHandleArray< IMaterialEffectsUpdator > m_updaters
Array of MultipleScattering updaters.
BooleanProperty m_printRzOutput
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateInsideVolume(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Surface &sf, const Layer *associatedLayer, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Private method for extrapolation in final volume to destination surface.
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateToDestinationLayer(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Surface &sf, const Layer &lay, const TrackingVolume &tvol, const Layer *startLayer, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Private to extrapolate to the destination layer + surface.
std::pair< std::unique_ptr< TrackParameters >, const Layer * > extrapolateToNextActiveLayerMImpl(const EventContext &ctx, const IPropagator &prop, const TrackParameters &parm, PropDirection dir, const BoundaryCheck &bcheck, std::vector< const Trk::TrackStateOnSurface * > &material, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Actual heavy lifting implementation for extrapolateToNextActiveLayerM.
std::unique_ptr< TrackParameters > extrapolateToVolumeImpl(const EventContext &ctx, const IPropagator &prop, const TrackParameters &parm, const Trk::TrackingVolume &vol, PropDirection dir=anyDirection, ParticleHypothesis particle=pion) const
Actual heavy lifting implementation for extrapolateToVolume.
StringArrayProperty m_propNames
Gaudi::Accumulators::Counter m_extrapolateCalls
number of calls: extrapolate() method
Gaudi::Accumulators::Counter m_layerSwitched
number of layers that have been switched
Extrapolator(const std::string &, const std::string &, const IInterface *)
Constructor.
~Extrapolator()
Destructor.
static const unsigned int m_maxNavigSurf
BooleanProperty m_navigationStatistics
Trk::CacheOwnedPtr< Trk::TrackParameters > extrapolateImpl(const EventContext &ctx, Cache &cache, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
Actual heavy lifting implementation for extrapolate.
virtual StatusCode initialize() override
AlgTool initailize method.
Gaudi::Accumulators::Counter m_startThroughGlobalSearch
navigation intialization
ToolHandle< IPropagator > m_stepPropagator
Navigator for TrackingGeometry and magnetic fiels acces.
Gaudi::Accumulators::Counter m_navigationBreakLoop
number of navigation breaks due to loop
UnsignedIntegerProperty m_maxMethodSequence
bool radialDirectionCheck(const EventContext &ctx, const IPropagator &prop, const TrackParameters &startParm, const TrackParameters &parsOnLayer, const TrackingVolume &tvol, PropDirection dir=anyDirection, ParticleHypothesis particle=pion) const
Check for punchThrough in case of radial (perpendicular) direction change, returns true if the radial...
Trk::MagneticFieldProperties m_fieldProperties
Gaudi::Accumulators::Counter m_startThroughRecall
navigation intialization
BooleanProperty m_fastField
Gaudi::Accumulators::Counter m_destinationThroughAssociation
navigation intialization
BooleanProperty m_useMuonMatApprox
PropDirection initializeNavigation(const EventContext &ctx, Cache &cache, const Trk::IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > startPars, const Trk::Surface &destSurface, Trk::PropDirection dir, ParticleHypothesis particle, Trk::CacheOwnedPtr< Trk::TrackParameters > &referenceParameters, const Trk::Layer *&associatedLayer, const Trk::TrackingVolume *&associatedVolume, const Trk::TrackingVolume *&destinationVolume) const
Private method for Initial Extrapolation setup -> overwrites the given pointers for the start and des...
ToolHandle< INavigator > m_navigator
Array of Material updatersc.
Trk::CacheOwnedPtr< Trk::TrackParameters > insideVolumeStaticLayers(const EventContext &ctx, Cache &cache, bool toBoundary, const IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Layer *associatedLayer, const TrackingVolume &tvol, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const
A) call from extrapolateInsideVolume or toBoundary, if it is to boundary, the return parameters are t...
const IPropagator * subPropagator(const TrackingVolume &tvol) const
Access the subPropagator to the given volume.
BooleanProperty m_useDenseVolumeDescription
Gaudi::Accumulators::Counter m_startThroughAssociation
navigation intialization
std::unique_ptr< Surface > m_referenceSurface
UnsignedIntegerProperty m_maxRecursion
Gaudi::Accumulators::Counter m_destinationThroughRecall
navigation intialization
Gaudi::Accumulators::Counter m_navigationBreakVolumeSignature
number of navigation breaks due to distance increase
const IMaterialEffectsUpdator * subMaterialEffectsUpdator(const TrackingVolume &tvol) const
Access the subPropagator to the given volume.
Gaudi::Accumulators::Counter m_extrapolateDirectlyCalls
number of calls: extrapolateDirectly() method
BooleanProperty m_includeMaterialEffects
virtual TrackParametersUVector extrapolateStepwise(const EventContext &ctx, const TrackParameters &parm, const Surface &sf, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion) const override final
Extrapolation method where a step-wise navigation to the destination surface is performed.
virtual std::pair< std::unique_ptr< TrackParameters >, const Layer * > extrapolateToNextActiveLayerM(const EventContext &ctx, const TrackParameters &parm, PropDirection dir, const BoundaryCheck &bcheck, std::vector< const Trk::TrackStateOnSurface * > &material, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const override final
Extrapolation to the next active layer with material collection.
void addMaterialEffectsOnTrack(const EventContext &ctx, Cache &cache, const Trk::IPropagator &prop, Trk::CacheOwnedPtr< Trk::TrackParameters > parm, const Trk::Layer &lay, const Trk::TrackingVolume &vol, Trk::PropDirection propDir, Trk::ParticleHypothesis) const
helper method for MaterialEffectsOnTrack to be added
StringArrayProperty m_updatNames
Cache class to allow passing information to/between calls.
Interface class for the updater AlgTool, it inherits from IAlgTool.
virtual std::unique_ptr< TrackParameters > update(ICache &icache, const TrackParameters *param, const Layer &sf, PropDirection dir=alongMomentum, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const =0
Updator interface (full update for a layer): The parameters are given as a pointer owned by the calle...
virtual std::unique_ptr< TrackParameters > postUpdate(ICache &icache, const TrackParameters &param, const Layer &sf, PropDirection dir=alongMomentum, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const =0
Updator interface (pre-update for a layer): The parameters are given as a pointer owned by the caller...
virtual std::unique_ptr< TrackParameters > preUpdate(ICache &icache, const TrackParameters *param, const Layer &sf, PropDirection dir=alongMomentum, ParticleHypothesis particle=pion, MaterialUpdateMode matupmode=addNoise) const =0
Updator interface (pre-update for a layer): The parameters are given as a pointer owned by the caller...
Interface class IPropagators It inherits from IAlgTool.
Definition IPropagator.h:55
virtual std::unique_ptr< TrackParameters > propagateParameters(const EventContext &ctx, const TrackParameters &parm, const Surface &sf, PropDirection dir, const BoundaryCheck &bcheck, const MagneticFieldProperties &mprop, ParticleHypothesis particle=pion, bool returnCurv=false, const TrackingVolume *tVol=nullptr) const =0
Main propagation method for parameters only.
virtual std::unique_ptr< NeutralParameters > propagate(const NeutralParameters &parameters, const Surface &sf, PropDirection dir, const BoundaryCheck &bcheck, bool returnCurv=false) const =0
Main propagation method for NeutralParameters.
virtual std::unique_ptr< TrackParameters > propagateM(const EventContext &ctx, const TrackParameters &parm, std::vector< DestSurf > &sfs, PropDirection dir, const MagneticFieldProperties &mprop, ParticleHypothesis particle, std::vector< unsigned int > &solutions, std::vector< const Trk::TrackStateOnSurface * > *matstates, std::vector< std::pair< std::unique_ptr< Trk::TrackParameters >, int > > *intersections, double &path, bool usePathLim=false, bool returnCurv=false, const TrackingVolume *tVol=nullptr, Trk::ExtrapolationCache *cache=nullptr) const =0
Propagation interface: The propagation method with internal material collection.
int value() const
layerIndex expressed in an integer
Definition LayerIndex.h:71
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
size_t compatibleSurfaces(std::vector< SurfaceIntersection > &cSurfaces, const TrackParameters &pars, PropDirection pdir, const BoundaryCheck &bcheck, bool materialSurfacesOnly=true, const Surface *startSurface=nullptr, const Surface *endSurface=nullptr, const ICompatibilityEstimator *ice=nullptr) const
get compatible surfaces starting from charged parameters
int layerType() const
get the Layer coding
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
const MaterialProperties * fullUpdateMaterialProperties(const TrackParameters &par) const
getting the MaterialProperties back - for full update
Definition Layer.cxx:169
virtual bool isOnLayer(const Amg::Vector3D &gp, const BoundaryCheck &bcheck=BoundaryCheck(true)) const
isOnLayer() method, using isOnSurface() with Layer specific tolerance
Definition Layer.cxx:135
const Layer * nextLayer(const Amg::Vector3D &gp, const Amg::Vector3D &udir) const
getting the next/previous Layer if registered - unit for direction vector required
Definition Layer.cxx:161
const SurfaceArray * surfaceArray() const
Return the entire SurfaceArray, returns nullptr if no SurfaceArray.
const LayerMaterialProperties * layerMaterialProperties() const
getting the LayerMaterialProperties including full/pre/post update
const LayerIndex & layerIndex() const
get the layerIndex
virtual double postUpdateMaterialFactor(const TrackParameters &, PropDirection) const
getting the MaterialProperties back - for pre-update
Definition Layer.h:150
virtual double preUpdateMaterialFactor(const TrackParameters &, PropDirection) const
getting the MaterialProperties back - for pre-update
Definition Layer.h:144
double thickness() const
Return the Thickness of the Layer.
const TrackingVolume * enclosingTrackingVolume() const
get the confining TrackingVolume
const Surface * subSurface(const Amg::Vector3D &gp) const
If no subSurface array is defined or no subSurface can be found to the given Amg::Vector3D,...
Definition Layer.cxx:107
magnetic field properties to steer the behavior of the extrapolation
represents the full description of deflection and e-loss of a track in material.
Material with information about thickness of material.
float thicknessInX0() const
Return the radiationlength fraction.
float x0() const
Return the radiation length.
float x0() const
Definition Material.h:227
float zOverAtimesRho() const
access to members
Definition Material.h:226
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
std::unique_ptr< ParametersBase< DIM, T > > uniqueClone() const
clone method for polymorphic deep copy returning unique_ptr; it is not overriden, but uses the existi...
represents a deflection of the track caused through multiple scattering in material.
virtual double r() const =0
Interface method for the maximal extension or the radius.
Abstract Base Class for tracking surfaces.
const TrkDetElementBase * associatedDetectorElement() const
return associated Detector Element
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const =0
fast straight line distance evaluation to Surface
virtual const Trk::Surface * baseSurface() const
return the base surface (simplified for persistification)
virtual double pathCorrection(const Amg::Vector3D &pos, const Amg::Vector3D &mom) const
the pathCorrection for derived classes with thickness - it reflects if the direction projection is po...
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
virtual constexpr SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
virtual const Amg::Vector3D & globalReferencePoint() const
Returns a global reference point on the surface, for PlaneSurface, StraightLineSurface,...
virtual bool isOnSurface(const Amg::Vector3D &glopo, const BoundaryCheck &bchk=true, double tol1=0., double tol2=0.) const
This method returns true if the GlobalPosition is on the Surface for both, within or without check of...
Definition Surface.cxx:123
virtual const SurfaceBounds & bounds() const =0
Surface Bounds method.
const Trk::Layer * associatedLayer() const
return the associated Layer
const Amg::Vector3D & center() const
Returns the center position of the Surface.
represents the track state (measurement, material, fit parameters and quality) at a surface.
const DataVector< const TrackParameters > * trackParameters() const
Return a pointer to a vector of TrackParameters.
std::vector< const Trk::DetachedTrackingVolume * > lowestDetachedTrackingVolumes(const Amg::Vector3D &gp) const
return the vector of lowest detached tracking Volume(->overlaps)
const TrackingVolume * trackingVolume(const std::string &name) const
return the tracking Volume by name, 0 if it doesn't exist
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Forward the associated Layer information.
const TrackingVolume * highestTrackingVolume() const
return the world
const TrackingVolume * lowestStaticTrackingVolume(const Amg::Vector3D &gp) const
return the lowest static tracking Volume
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
const LayerArray * confinedLayers() const
Return the subLayer array.
GeometrySignature geometrySignature() const
return the Signature
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Return the associated Layer.
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
const TrackingVolume * associatedSubVolume(const Amg::Vector3D &gp) const
Return the associated sub Volume, returns THIS if no subVolume exists.
std::vector< std::shared_ptr< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
const std::string & volumeName() const
Returns the VolumeName - for debug reason, might be depreciated later.
const Layer * nextLayer(const Amg::Vector3D &gp, const Amg::Vector3D &mom, bool asres=true, bool skipNavLayer=false) const
Return the next Layer if existing, NULL if no next layer corresponds.
ArraySpan< DetachedTrackingVolume const *const > confinedDetachedVolumes() const
Return detached subVolumes - not the ownership.
virtual bool isAlignable() const
ArraySpan< Layer const *const > confinedArbitraryLayers() const
Return the confined subLayer array.
ArraySpan< TrackingVolume const *const > confinedDenseVolumes() const
Return unordered subVolumes - not the ownership.
Base class for all volumes inside the tracking realm, it defines the interface for inherited Volume c...
Definition Volume.h:36
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition Volume.cxx:72
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
std::string getToolSuffix(const std::string &fullToolName)
Return the name suffix, e.g. return 'myNiceTool' from 'ToolSvc.myNiceTool'.
unsigned int numberOfUniqueEntries(const std::vector< std::string > &nameVector)
Give the number of unique entries in a vector.
std::string possibleToolNameError(const std::vector< std::string > &toolNameVector)
Give an error message if tool names are invalid; empty string if good.
Ensure that the ATLAS eigen extensions are properly loaded.
PropDirection
PropDirection, enum for direction of the propagation.
@ oppositeMomentum
@ alongMomentum
@ anyDirection
static const Amg::Transform3D s_idTransform
idendity transformation
std::span< T > ArraySpan
ParametersBase< NeutralParametersDim, Neutral > NeutralParameters
BoundarySurfaceFace
Enum to describe the position of the BoundarySurface respectively to the frame orientatin of the volu...
CurvilinearParametersT< TrackParametersDim, Charged, PlaneSurface > CurvilinearParameters
ComparisonFunction< TrackParameters > TrkParametersComparisonFunction
@ FastField
call the fast field access method of the FieldSvc
@ FullField
Field is set to be realistic, but within a given Volume.
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
MaterialUpdateMode
This is a steering enum to force the material update it can be: (1) addNoise (-1) removeNoise Second ...
std::pair< std::shared_ptr< Material >, int > IdentifiedMaterial
@ NumberOfSignatures
std::vector< std::unique_ptr< Trk::TrackParameters > > TrackParametersUVector
ParametersBase< TrackParametersDim, Charged > TrackParameters
T * CacheOwnedPtr
@ active
Definition Layer.h:47
Definition index.py:1
const Surface * m_destinationSurface
the boundary volume check
const Layer * m_lastMaterialLayer
cache for collecting the total X0 ans Eloss
std::string elossPointerErrorMsg(int lineNumber=0) const
String error message if the cache has a problem.
const Volume * m_boundaryVolume
Destination Surface for recall.
const Trk::EnergyLoss * m_cacheEloss
cache of TrackStateOnSurfaces
void retrieveBoundaries()
Retrieve boundaries.
const Trk::TrackingVolume * volume(const EventContext &, const Amg::Vector3D &gp) const
void setRecallInformation(const Surface &, const Layer &, const TrackingVolume &)
Private method for setting recall Information.
bool elossPointerOverwritten() const
Check cache integrity.
std::vector< std::pair< const Trk::Surface *, Trk::BoundaryCheck > > m_navigSurfs
std::array< unsigned short, kNRecursionValues > m_recursionCount
const TrackingVolume * m_recallTrackingVolume
const Layer * m_recallLayer
Destination TrackingVolume for recall.
std::pair< unsigned int, unsigned int > m_denseResolved
double m_path
Pointer (not owning) pointing.
std::vector< Trk::IMaterialEffectsUpdator::ICache > m_MaterialUpCache
internal switch for resolved configuration
unsigned int m_layerResolved
void addOneNavigationLayer(const Trk::TrackingVolume *pDetVol, const Trk::Layer *pLayer, bool boundaryCheck=true)
Add one layer and navigLayer.
std::vector< DestSurf > m_detachedBoundaries
void populateMatEffUpdatorCache(const std::vector< const IMaterialEffectsUpdator * > &updaters)
std::vector< std::pair< const Trk::TrackingVolume *, const Trk::Layer * > > m_navigLays
unsigned int m_nPropagations
const Surface * m_recallSurface
Destination Layer for recall.
std::vector< DestSurf > m_staticBoundaries
const Trk::TrackingVolume * m_highestVolume
Trk::ExtrUniquePtrHolder< Trk::TrackParameters > m_ownedPtrs
parameters to be used for final propagation in case of fallback
IMaterialEffectsUpdator::ICache & subMaterialEffectsUpdatorCache(const TrackingVolume &tvol)
Get the IMaterialEffectsUpdator::ICache for the MaterialEffectsUpdator.
Trk::TrackParameters * m_lastValidParameters
return helper for parameters and boundary
std::vector< std::pair< const Trk::TrackingVolume *, unsigned int > > m_navigVolsInt
std::vector< const Trk::TrackStateOnSurface * > * m_matstates
void setTrackingGeometry(const Trk::INavigator &navigator, const EventContext &ctx)
std::vector< std::pair< const Trk::DetachedTrackingVolume *, unsigned int > > m_detachedVols
std::string to_string(const std::string &txt) const
String representation of cache.
std::vector< std::pair< const Trk::TrackingVolume *, unsigned int > > m_denseVols
std::vector< DestSurf > m_navigBoundaries
const Trk::TrackingGeometry * m_trackingGeometry
std::unique_ptr< identifiedParameters_t > m_identifiedParameters
enum Trk::Cache::EStatus m_status
void copyToNavigationSurfaces()
Insert navigation surfaces from layers, dense boundaries, navig boundaries and detached boundaries.
Trk::ExtrapolationCache * m_extrapolationCache
cache pointer for Eloss
ParametersNextVolume m_parametersAtBoundary
Caches per MaterialUpdator.
const Trk::TrackingVolume * m_currentStatic
const Trk::TrackingVolume * m_currentDense
std::vector< DestSurf > m_layers
TrackParametersUVector * m_parametersOnDetElements
cache layer with last material update
unsigned int m_methodSequence
std::vector< DestSurf > m_denseBoundaries
useful struct for a single navigation cell
Definition INavigator.h:38
const TrackingVolume * nextVolume
Definition INavigator.h:40
BoundarySurfaceFace exitFace
Definition INavigator.h:43
std::unique_ptr< TrackParameters > parametersOnBoundary
Definition INavigator.h:42
void boundaryInformation(const TrackingVolume *tvol, Trk::TrackParameters *nextPars, Trk::TrackParameters *navPars, BoundarySurfaceFace face=undefinedFace)
reset the boundary information by invalidating it
Trk::TrackParameters * navParameters
const TrackingVolume * nextVolume
< the members
Trk::TrackParameters * nextParameters