ATLAS Offline Software
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 //
39 #include "TrkSurfaces/DiscBounds.h"
44 //
47 #include "TrkVolumes/Volume.h"
48 //
51 //
52 #include <utility>
53 #include <cstdint>
54 #include <memory>
55 
56 
57 namespace {
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  {
65  ++(*m_counter)[Trk::Cache::kCurrentRecursionCount];
67  }
68  ~RecursionCounter() { --(*m_counter)[Trk::Cache::kCurrentRecursionCount]; }
69  private:
70  std::array<unsigned short,Trk::Cache::kNRecursionValues> *m_counter;
71  };
72 }
73 
74 namespace {
75 constexpr double s_distIncreaseTolerance = 100. * Gaudi::Units::millimeter;
76 constexpr unsigned int INVALIDPROPAGATORS = Trk::NumberOfSignatures+3;
77 
81 int
82 radialDirection(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 }
93 std::string
94 layerRZoutput(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 }
103 std::string
104 momentumOutput(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
116 Trk::Extrapolator::Extrapolator(const std::string& t, const std::string& n, const IInterface* p)
118  , m_subPropagators(Trk::NumberOfSignatures)
119  , m_subupdaters(Trk::NumberOfSignatures)
120  , m_numOfValidPropagators(INVALIDPROPAGATORS)
121 {
122  declareInterface<IExtrapolator>(this);
123 }
124 
125 // destructor
127 
128 // Athena standard methods
129 // initialize
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 
137  m_fieldProperties = m_fastField ? Trk::MagneticFieldProperties(Trk::FastField)
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(); };
187  m_propagators.begin(), m_propagators.end(), fullPropagatorNames.begin(), extractNameFromTool);
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]));
197  if (TrkExTools::numberOfUniqueEntries(m_propNames) !=
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]));
210  if (TrkExTools::numberOfUniqueEntries(m_updatNames) !=
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
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  }
288  if (m_navigationStatistics) {
289  ATH_MSG_INFO(" Perfomance Statistics : ");
290  ATH_MSG_INFO(" [P] Method Statistics ------- ------------------------------------");
291  ATH_MSG_INFO(" -> Number of extrapolate() calls : " << m_extrapolateCalls);
292  ATH_MSG_INFO(
293  " -> Number of extrapolateBlindly() calls : " << m_extrapolateBlindlyCalls);
294  ATH_MSG_INFO(
295  " -> Number of extrapolateDirectly() calls : " << m_extrapolateDirectlyCalls);
296  ATH_MSG_INFO(
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 -------------------------------------");
300  ATH_MSG_INFO(
301  " -> Number of start associations : " << m_startThroughAssociation);
302  ATH_MSG_INFO(" -> Number of start recalls : " << m_startThroughRecall);
303  ATH_MSG_INFO(
304  " -> Number of start global searches : " << m_startThroughGlobalSearch);
305  ATH_MSG_INFO(
306  " -> Number of destination associations : " << m_destinationThroughAssociation);
307  ATH_MSG_INFO(
308  " -> Number of destination recalls : " << m_destinationThroughRecall);
309  ATH_MSG_INFO(" -> Number of destination global searches : "
310  << m_destinationThroughGlobalSearch);
311  ATH_MSG_INFO("[P] Navigation Breaks ---------------------------------------------");
312  ATH_MSG_INFO(
313  " -> Number of navigation breaks: loop : " << m_navigationBreakLoop);
314  ATH_MSG_INFO(
315  " -> Number of navigation breaks: oscillation : " << m_navigationBreakOscillation);
316  ATH_MSG_INFO(
317  " -> Number of navigation breaks: no volume found : " << m_navigationBreakNoVolume);
318  ATH_MSG_INFO(
319  " -> Number of navigation breaks: dist. increase : " << m_navigationBreakDistIncrease);
320  ATH_MSG_INFO(" -> Number of navigation breaks: dist. increase : "
321  << m_navigationBreakVolumeSignature);
322  if (m_navigationBreakDetails) {
323  ATH_MSG_DEBUG(" Detailed output for Navigation breaks : ");
324  ATH_MSG_DEBUG(" o " << m_navigationBreakLoop
325  << " loops occured in the following volumes: ");
326  ATH_MSG_DEBUG(" o " << m_navigationBreakOscillation
327  << " oscillations occured in following volumes: ");
328  ATH_MSG_DEBUG(" o " << m_navigationBreakNoVolume
329  << " times no next volume found of volumes: ");
330  ATH_MSG_DEBUG(" o " << m_navigationBreakDistIncrease
331  << " distance increases detected at volumes: ");
332  ATH_MSG_DEBUG(" o " << m_navigationBreakVolumeSignature
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
345 std::unique_ptr<Trk::TrackParameters>
347  const Trk::TrackParameters& parm,
348  const Trk::Surface& sf,
350  const Trk::BoundaryCheck& bcheck,
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  }
359  return extrapolateDirectlyImpl(
360  ctx, (*currentPropagator), parm, sf, dir, bcheck, particle);
361 }
362 
363 //Public Charged Particle Extrapolation method
364 std::unique_ptr<Trk::TrackParameters>
365 Trk::Extrapolator::extrapolate(const EventContext& ctx,
366  const TrackParameters& parm,
367  const Surface& sf,
369  const BoundaryCheck& bcheck,
371  MaterialUpdateMode matupmode,
372  Trk::ExtrapolationCache* extrapolationCache) const
373 {
374  Cache cache(m_propStat);
375  // Material effect updator cache
376  Trk::CacheOwnedPtr<Trk::TrackParameters> clonedInput = cache.m_ownedPtrs.push(parm.uniqueClone());
377  cache.populateMatEffUpdatorCache(m_subupdaters);
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
384 std::unique_ptr<Trk::NeutralParameters>
386  const Surface& sf,
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,
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
421 std::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);
459  Trk::CacheOwnedPtr<Trk::TrackParameters> clonedInput = cache.m_ownedPtrs.push(parm.uniqueClone());
460  cache.populateMatEffUpdatorCache(m_subupdaters);
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
470 std::vector<const Trk::TrackStateOnSurface*>*
471 Trk::Extrapolator::extrapolateM(const EventContext& ctx,
472  const TrackParameters& parm,
473  const Surface& sf,
475  const BoundaryCheck& bcheck,
477  Trk::ExtrapolationCache* extrapolationCache) const
478 {
479 
480  Cache cache(m_propStat);
481  // Material effect updator cache
482  cache.populateMatEffUpdatorCache(m_subupdaters);
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
491  Trk::CacheOwnedPtr<Trk::TrackParameters> clonedInput = cache.m_ownedPtrs.push(parm.uniqueClone());
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
510 std::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
534  cache.populateMatEffUpdatorCache(m_subupdaters);
535  // extrapolate to subdetector boundary
536  auto *cloneInput = cache.m_ownedPtrs.push(parm.uniqueClone());
537  Trk::CacheOwnedPtr<Trk::TrackParameters> subDetBounds = extrapolateToVolumeWithPathLimit(
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(),
545  cache.m_currentStatic ? cache.m_currentStatic->geometrySignature() : 0));
546  if (cache.m_currentStatic && cache.m_currentStatic->geometrySignature() == destination) {
547  break;
548  }
549  if (!cache.m_parametersAtBoundary.nextVolume) {
550  break; // world boundary
551  }
552  subDetBounds = extrapolateToVolumeWithPathLimit(
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
562 std::pair<std::unique_ptr<Trk::TrackParameters>, const Trk::Layer*>
564  const EventContext& ctx,
565  const TrackParameters& parm,
567  const BoundaryCheck& bcheck,
568  std::vector<const Trk::TrackStateOnSurface*>& material,
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
587 std::unique_ptr<Trk::TrackParameters>
589  const Trk::TrackParameters& parm,
590  const Trk::TrackingVolume& vol,
593 {
594  // take the volume signatrue to define the right propagator
595  const IPropagator* currentPropagator =
596  !m_subPropagators.empty() ? m_subPropagators[vol.geometrySignature()]
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,
622 
623  Cache cache(m_propStat);
624  // statistics && sequence output ----------------------------------------
625  ++m_extrapolateStepwiseCalls;
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
633  // Material effect updator cache
634  cache.populateMatEffUpdatorCache(m_subupdaters);
636  Trk::CacheOwnedPtr<Trk::TrackParameters> clonedInput = cache.m_ownedPtrs.push(parm.uniqueClone());
637  // run the extrapolation
638  Trk::CacheOwnedPtr<Trk::TrackParameters> parameterOnSf = extrapolateImpl(
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 
651 std::pair<std::unique_ptr<Trk::TrackParameters>, const Trk::Layer*>
653  const EventContext& ctx,
654  const IPropagator& prop,
655  const Trk::TrackParameters& parm,
657  const BoundaryCheck& bcheck,
658  std::vector<const Trk::TrackStateOnSurface*>& material,
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
668  cache.populateMatEffUpdatorCache(m_subupdaters);
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 ?
698  (cache.m_parametersAtBoundary.nextVolume->geometrySignature() == Trk::Calo && m_useDenseVolumeDescription)) {
699  staticVol = cache.m_parametersAtBoundary.nextVolume;
700  nextPar = cache.m_parametersAtBoundary.nextParameters;
701  ATH_MSG_DEBUG(" [+] Static volume boundary: continue loop over active layers in '"
702  << staticVol->volumeName() << "'.");
703  } else { // MSentrance
704  nextPar = cache.m_parametersAtBoundary.nextParameters;
706  return {cache.m_ownedPtrs.move(nextPar), nullptr};
707  }
708  } else if (cache.m_parametersAtBoundary.nextParameters) { // outer boundary
709  nextPar = cache.m_parametersAtBoundary.nextParameters;
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,
733  const BoundaryCheck& bcheck,
735  MaterialUpdateMode matupmode) const
736 {
737  RecursionCounter counter(cache.m_recursionCount);
738  if (cache.m_recursionCount[Trk::Cache::kCurrentRecursionCount]>m_maxRecursion) {
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(...) ");
746  if (cache.m_methodSequence > m_maxMethodSequence) {
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()) {
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 ||
855  !m_useMuonMatApprox ||
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) ||
902  (staticVol->geometrySignature() != Trk::MS && m_useDenseVolumeDescription);
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 =
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  }
1158  cache.copyToNavigationSurfaces();
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);
1278  cache.m_extrapolationCache->updateEloss(eloss.meanIoni(),
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 =
1337  subMaterialEffectsUpdator(*cache.m_currentStatic);
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 &&
1480  ATH_MSG_DEBUG(
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 =
1493  subMaterialEffectsUpdator(*cache.m_currentStatic);
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) {
1680  return extrapolateToNextMaterialLayer(
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) {
1722  return extrapolateToNextMaterialLayer(
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,
1747  const Trk::AlignableTrackingVolume* vol,
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 {
1781  currVol = cache.m_trackingGeometry->lowestStaticTrackingVolume(gp);
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 
1983 std::unique_ptr<Trk::TrackParameters>
1985  const IPropagator& prop,
1986  const Trk::TrackParameters& parm,
1987  const Trk::Surface& sf,
1989  const Trk::BoundaryCheck& bcheck,
1991 {
1992  // statistics && sequence output ----------------------------------------
1993  ++m_extrapolateDirectlyCalls;
1994  return prop.propagate(ctx, parm, sf, dir, bcheck, m_fieldProperties, particle);
1995 }
1996 
1997 std::unique_ptr<Trk::TrackParameters>
1999  const IPropagator& prop,
2000  const TrackParameters& parm,
2001  const TrackingVolume& vol,
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;
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);
2046  Trk::CacheOwnedPtr<Trk::TrackParameters> cloneInput = cache.m_ownedPtrs.push(parm.uniqueClone());
2047  // Material effect updator cache
2048  cache.populateMatEffUpdatorCache(m_subupdaters);
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);
2068  Trk::CacheOwnedPtr<Trk::TrackParameters> cloneInput = cache.m_ownedPtrs.push(parm.uniqueClone());
2069  // Material effect updator cache
2070  cache.populateMatEffUpdatorCache(m_subupdaters);
2071  returnParms = cache.m_ownedPtrs.move(
2072  extrapolateImpl(ctx, cache, prop, cloneInput, *((*rsIter).first),
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 
2090 Trk::Extrapolator::extrapolateImpl(const EventContext& ctx,
2091  Cache& cache,
2092  const IPropagator& prop,
2094  const Trk::Surface& sf,
2096  const Trk::BoundaryCheck& bcheck,
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 ----------------------------------------
2121  ++m_extrapolateCalls;
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 &&
2217  cache.m_methodSequence < m_maxMethodSequence) {
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
2227  ++m_navigationBreakVolumeSignature;
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) {
2269  ATH_MSG_ERROR(
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;
2289  } if (!cache.m_parametersAtBoundary.nextParameters ||
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
2300  extrapolateToVolumeBoundary(ctx,
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) {
2359  ATH_MSG_DEBUG(
2360  "last step:" << (nextParameters->position() - lastParameters->position()).mag());
2361  }
2362  ATH_MSG_DEBUG("- Reason : Loop detected in TrackingVolume '"
2363  << nextVolume->volumeName() << "'");
2364  // statistics
2365  ++m_navigationBreakLoop;
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 &&
2395  !m_stopWithUpdateZero) {
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()))) {
2435  ATH_MSG_DEBUG(
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
2463  if (m_stopWithNavigationBreak || m_stopWithUpdateZero) {
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
2473  Trk::CacheOwnedPtr<Trk::TrackParameters> resultParameters =
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 
2527 Trk::Extrapolator::extrapolateImpl(const EventContext& ctx,
2528  Cache& cache,
2529  const IPropagator& prop,
2531  const std::vector<MaterialEffectsOnTrack>& sfMeff,
2532  const TrackingVolume& tvol,
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 =
2568  cache.subMaterialEffectsUpdatorCache(tvol);
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 
2586 Trk::Extrapolator::extrapolateImpl(const EventContext& ctx,
2587  Cache& cache,
2589  const Surface& sf,
2591  const BoundaryCheck& bcheck,
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  }
2615  ATH_MSG_ERROR(
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,
2628  const Trk::Volume* boundaryVol) const
2629 {
2630  // statistics && sequence output ----------------------------------------
2631  ++m_extrapolateBlindlyCalls;
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,
2663  const BoundaryCheck& bcheck,
2665  MaterialUpdateMode matupmode) const
2666 {
2667  // ---> C) detached volumes exist
2668  if (!tvol.confinedDetachedVolumes().empty()) {
2669  return extrapolateWithinDetachedVolumes(
2670  ctx, cache, prop, parm, sf, tvol, dir, bcheck, particle, matupmode);
2671  }
2672  // ---> A) static layers exist
2673  return insideVolumeStaticLayers(
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,
2685  const BoundaryCheck& bcheck,
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;
2766  Trk::CacheOwnedPtr<Trk::TrackParameters> onNextLayer = extrapolateToNextMaterialLayer(
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 &&
2819  m_useDenseVolumeDescription))) {
2821  if (last_boundary_parameters &&
2822  last_boundary_parameters == cache.m_parametersAtBoundary.nextParameters) {
2824  " [!] Already tried parameters at boundary -> exit: pos="
2825  << positionOutput(cache.m_parametersAtBoundary.nextParameters->position())
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="
2834  << positionOutput(cache.m_parametersAtBoundary.nextParameters->position())
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 
2850 void
2852  Cache& cache,
2853  const IPropagator& prop,
2855  const Layer* assocLayer,
2856  const TrackingVolume& tvol,
2858  const BoundaryCheck& bcheck,
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
2870  Trk::CacheOwnedPtr<Trk::TrackParameters> inside_volume_static_layer(insideVolumeStaticLayers(
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 "
2874  << positionOutput(cache.m_parametersAtBoundary.navParameters->position()));
2875  }
2876 }
2877 
2880  Cache& cache,
2881  bool toBoundary,
2882  const IPropagator& prop,
2884  const Trk::Layer* assocLayer,
2885  const TrackingVolume& tvol,
2887  const BoundaryCheck& bcheck,
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 =
3002  cache.subMaterialEffectsUpdatorCache(tvol);
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) {
3011  addMaterialEffectsOnTrack(
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
3109  Trk::CacheOwnedPtr<Trk::TrackParameters> updateNext = extrapolateFromLayerToLayer(
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.");
3231  if (m_includeMaterialEffects) {
3232 
3233  const IMaterialEffectsUpdator* currentUpdator = m_subupdaters[tvol.geometrySignature()];
3234  IMaterialEffectsUpdator::ICache& currentUpdatorCache =
3235  cache.subMaterialEffectsUpdatorCache(tvol);
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) {
3245  addMaterialEffectsOnTrack(
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,
3274  const BoundaryCheck& bcheck,
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,
3389  const BoundaryCheck& bcheck,
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 =
3413  cache.subMaterialEffectsUpdatorCache(tvol);
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) {
3427  addMaterialEffectsOnTrack(
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 
3447 std::pair<Trk::CacheOwnedPtr<Trk::TrackParameters>, bool>
3449  Cache& cache,
3450  const IPropagator& prop,
3452  const Layer& lay,
3453  const TrackingVolume& tvol,
3455  const BoundaryCheck& bcheck,
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 =
3468  cache.subMaterialEffectsUpdatorCache(tvol);
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 
3545 void
3546 Trk::Extrapolator::overlapSearch(const EventContext& ctx,
3547  Cache& cache,
3548  const IPropagator& prop,
3551  const Layer& lay,
3552  const TrackingVolume& /*tvol*/,
3554  const BoundaryCheck& bcheck, // bcheck
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,
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
3762  ++m_startThroughRecall;
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
3769  ++m_startThroughGlobalSearch;
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 {
3790  ++m_startThroughAssociation;
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) {
3848  ++m_destinationThroughAssociation;
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 ----------
3856  ++m_destinationThroughRecall;
3857  } else if (!destVolume) {
3858  // (3) GLOBAL SEARCH
3859  destinationSearchType = "global search";
3860  ++m_destinationThroughGlobalSearch;
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 
3905 bool
3907  const IPropagator& prop,
3908  const TrackParameters& startParm,
3909  const TrackParameters& parsOnLayer,
3910  const TrackingVolume& tvol,
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 
3951 std::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 
3964 void
3966  Cache& cache,
3967  const Trk::IPropagator& prop,
3969  const Trk::Layer& lay,
3970  const Trk::TrackingVolume& /*tvol*/,
3971  Trk::PropDirection propDir,
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(),
3984  Trk::anyDirection, false, m_fieldProperties));
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,
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 ?
4165  if (cache.m_currentStatic && cache.m_currentStatic->geometrySignature() == Trk::Calo) {
4166  if (cache.m_currentStatic->isAlignable()) {
4167  const Trk::AlignableTrackingVolume* alignTV =
4168  static_cast<const Trk::AlignableTrackingVolume*>(cache.m_currentStatic);
4169  Trk::CacheOwnedPtr<Trk::TrackParameters> nextPar(extrapolateInAlignableTV(
4170  ctx, cache, *m_stepPropagator, currPar, nullptr, alignTV, dir, particle));
4171  if (nextPar) {
4172  return extrapolateToVolumeWithPathLimit(
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()) {
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 ||
4208  !m_useMuonMatApprox ||
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 =
4249  (cache.m_currentStatic->geometrySignature() == Trk::MS && m_useMuonMatApprox) ||
4250  (cache.m_currentStatic->geometrySignature() != Trk::MS && m_useDenseVolumeDescription);
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 =
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  }
4285  if (!active && cache.m_currentStatic->geometrySignature() == Trk::MS && m_useMuonMatApprox &&
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  }
4394  cache.copyToNavigationSurfaces();
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  }
4440  Trk::CacheOwnedPtr<Trk::TrackParameters> nextPar = cache.m_ownedPtrs.push(m_stepPropagator->propagate(
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 =
4509  subMaterialEffectsUpdator(*cache.m_currentStatic);
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  }
4565  return extrapolateToVolumeWithPathLimit(
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 =
4579  subMaterialEffectsUpdator(*cache.m_currentStatic);
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 ...)
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) {
4729  return extrapolateToVolumeWithPathLimit(
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) {
4770  return extrapolateToVolumeWithPathLimit(
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 }
Trk::ExtrapolationCache::updateX0
void updateX0(double x0)
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
Trk::Cache::m_detachedBoundaries
std::vector< DestSurf > m_detachedBoundaries
Definition: LocalExtrapolatorCache.h:86
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
make_hlt_rep.pars
pars
Definition: make_hlt_rep.py:90
Trk::Layer::isOnLayer
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
Trk::Extrapolator::overlapSearch
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.
Definition: Extrapolator.cxx:3546
Trk::Cache::m_denseVols
std::vector< std::pair< const Trk::TrackingVolume *, unsigned int > > m_denseVols
Definition: LocalExtrapolatorCache.h:92
EnergyLoss.h
Trk::Layer::postUpdateMaterialFactor
virtual double postUpdateMaterialFactor(const TrackParameters &, PropDirection) const
getting the MaterialProperties back - for pre-update
Definition: Layer.h:150
Trk::Surface::pathCorrection
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...
Trk::Cache::m_ownedPtrs
Trk::ExtrUniquePtrHolder< Trk::TrackParameters > m_ownedPtrs
parameters to be used for final propagation in case of fallback
Definition: LocalExtrapolatorCache.h:41
Trk::Cache::m_detachedVols
std::vector< std::pair< const Trk::DetachedTrackingVolume *, unsigned int > > m_detachedVols
Definition: LocalExtrapolatorCache.h:91
ScatteringAngles.h
TrkExTools::getToolSuffix
std::string getToolSuffix(const std::string &fullToolName)
Return the name suffix, e.g. return 'myNiceTool' from 'ToolSvc.myNiceTool'.
Definition: TrkExToolsStringUtility.cxx:14
Trk::IMaterialEffectsUpdator::ICache
Cache class to allow passing information to/between calls.
Definition: IMaterialEffectsUpdator.h:63
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::Extrapolator::finalize
virtual StatusCode finalize() override
AlgTool finalize method.
Definition: Extrapolator.cxx:277
Trk::Layer::fullUpdateMaterialProperties
const MaterialProperties * fullUpdateMaterialProperties(const TrackParameters &par) const
getting the MaterialProperties back - for full update
Definition: Layer.cxx:169
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:79
Trk::Cache::kMaxRecursionCount
@ kMaxRecursionCount
Definition: LocalExtrapolatorCache.h:100
Trk::TrackingVolume::nextLayer
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.
Definition: TrackingVolume.cxx:418
Trk::Surface::associatedDetectorElement
const TrkDetElementBase * associatedDetectorElement() const
return associated Detector Element
TrkExTools::numberOfUniqueEntries
unsigned int numberOfUniqueEntries(const std::vector< std::string > &nameVector)
Give the number of unique entries in a vector.
Definition: TrkExToolsStringUtility.cxx:45
Trk::NavigationCell::nextVolume
const TrackingVolume * nextVolume
Definition: INavigator.h:40
Trk::Cache::m_lastValidParameters
Trk::TrackParameters * m_lastValidParameters
return helper for parameters and boundary
Definition: LocalExtrapolatorCache.h:43
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
StraightLineSurface.h
Trk::NavigationCell::parametersOnBoundary
std::unique_ptr< TrackParameters > parametersOnBoundary
Definition: INavigator.h:42
DiscBounds.h
TrackParameters.h
GeometrySignature.h
Trk::DistanceSolution::toPointOfClosestApproach
double toPointOfClosestApproach() const
Distance to point of closest approach along direction.
Trk::MagneticFieldProperties
Definition: MagneticFieldProperties.h:31
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
PerigeeSurface.h
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
Trk::DistanceSolution
Definition: DistanceSolution.h:25
Trk::Volume::inside
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition: Volume.cxx:72
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Trk::oppositeMomentum
@ oppositeMomentum
Definition: PropDirection.h:21
Trk::TrackingVolume::geometrySignature
GeometrySignature geometrySignature() const
return the Signature
Trk::IPropagator::propagateM
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.
Trk::DistanceSolution::numberOfSolutions
int numberOfSolutions() const
Number of intersection solutions.
index
Definition: index.py:1
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Trk::Surface::straightLineDistanceEstimate
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const =0
fast straight line distance evaluation to Surface
Trk::ParametersBase::uniqueClone
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...
Definition: ParametersBase.h:97
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
IEnergyLossUpdator.h
Trk::Cache::m_MaterialUpCache
std::vector< Trk::IMaterialEffectsUpdator::ICache > m_MaterialUpCache
internal switch for resolved configuration
Definition: LocalExtrapolatorCache.h:47
Trk::Cache
Definition: LocalExtrapolatorCache.h:36
Trk::Cache::m_extrapolationCache
Trk::ExtrapolationCache * m_extrapolationCache
cache pointer for Eloss
Definition: LocalExtrapolatorCache.h:75
Trk::Cache::m_navigBoundaries
std::vector< DestSurf > m_navigBoundaries
Definition: LocalExtrapolatorCache.h:88
Trk::Extrapolator::collectIntersections
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.
Definition: Extrapolator.cxx:511
Trk::Cache::m_recallTrackingVolume
const TrackingVolume * m_recallTrackingVolume
Definition: LocalExtrapolatorCache.h:60
Trk::Cache::m_layers
std::vector< DestSurf > m_layers
Definition: LocalExtrapolatorCache.h:89
Trk::MaterialProperties::thicknessInX0
float thicknessInX0() const
Return the radiationlength fraction.
Trk::Extrapolator::addMaterialEffectsOnTrack
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
Definition: Extrapolator.cxx:3965
Trk::BinnedMaterial
Definition: BinnedMaterial.h:31
Trk::Cache::populateMatEffUpdatorCache
void populateMatEffUpdatorCache(const std::vector< const IMaterialEffectsUpdator * > &updaters)
Definition: LocalExtrapolatorCache.cxx:63
Trk::TrackingVolume::associatedSubVolume
const TrackingVolume * associatedSubVolume(const Amg::Vector3D &gp) const
Return the associated sub Volume, returns THIS if no subVolume exists.
Definition: TrackingVolume.cxx:530
Trk::Cache::m_parametersOnDetElements
TrackParametersUVector * m_parametersOnDetElements
cache layer with last material update
Definition: LocalExtrapolatorCache.h:70
module_driven_slicing.layers
layers
Definition: module_driven_slicing.py:113
Trk::Material::zOverAtimesRho
float zOverAtimesRho() const
access to members
Definition: Material.h:226
Trk::Cache::m_navigLays
std::vector< std::pair< const Trk::TrackingVolume *, const Trk::Layer * > > m_navigLays
Definition: LocalExtrapolatorCache.h:93
Trk::Cache::setRecallInformation
void setRecallInformation(const Surface &, const Layer &, const TrackingVolume &)
Private method for setting recall Information.
Definition: LocalExtrapolatorCache.cxx:72
Trk::Cache::retrieveBoundaries
void retrieveBoundaries()
Retrieve boundaries.
Definition: LocalExtrapolatorCache.cxx:118
Trk::Cache::resetRecallInformation
void resetRecallInformation()
Definition: LocalExtrapolatorCache.cxx:79
PlotCalibFromCool.ib
ib
Definition: PlotCalibFromCool.py:419
Trk::Extrapolator::insideVolumeStaticLayers
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...
Definition: Extrapolator.cxx:2879
ParticleTest.tp
tp
Definition: ParticleTest.py:25
Trk::TrackingVolume::confinedDetachedVolumes
ArraySpan< DetachedTrackingVolume const *const > confinedDetachedVolumes() const
Return detached subVolumes - not the ownership.
Trk::Cache::m_path
double m_path
Pointer (not owning) pointing.
Definition: LocalExtrapolatorCache.h:67
Trk::ScatteringAngles
represents a deflection of the track caused through multiple scattering in material.
Definition: ScatteringAngles.h:26
Trk::Extrapolator::extrapolateDirectlyImpl
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.
Definition: Extrapolator.cxx:1984
Layer.h
Trk::MaterialUpdateMode
MaterialUpdateMode
This is a steering enum to force the material update it can be: (1) addNoise (-1) removeNoise Second ...
Definition: MaterialUpdateMode.h:18
Trk::alongMomentum
@ alongMomentum
Definition: PropDirection.h:20
Trk::MaterialProperties::x0
float x0() const
Return the radiation length.
Trk::ParametersNextVolume::nextParameters
Trk::TrackParameters * nextParameters
Definition: ParametersNextVolume.h:17
Trk::Extrapolator::extrapolateBlindlyImpl
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.
Definition: Extrapolator.cxx:2621
Trk::EnergyLoss::sigmaRad
double sigmaRad() const
Trk::ParametersNextVolume::resetBoundaryInformation
void resetBoundaryInformation()
Definition: ParametersNextVolume.h:39
Trk::Extrapolator::extrapolateImpl
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.
Definition: Extrapolator.cxx:2090
Trk::Surface::globalReferencePoint
virtual const Amg::Vector3D & globalReferencePoint() const
Returns a global reference point on the surface, for PlaneSurface, StraightLineSurface,...
ExtrUniquePtrHolder.h
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
Trk::DistanceSolution::first
double first() const
Distance to first intersection solution along direction.
PlotCalibFromCool.multi
multi
Definition: PlotCalibFromCool.py:99
Trk::Extrapolator::~Extrapolator
~Extrapolator()
Destructor.
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
MuonR4::to_string
std::string to_string(const SectorProjector proj)
Definition: MsTrackSeeder.cxx:66
Trk::EnergyLoss::meanIoni
double meanIoni() const
Trk::Surface::center
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Trk::Calo
@ Calo
Definition: GeometrySignature.h:28
Trk::ParametersNextVolume::nextVolume
const TrackingVolume * nextVolume
< the members
Definition: ParametersNextVolume.h:16
Trk::Layer::compatibleSurfaces
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
Trk::Cache::kContinue
@ kContinue
Definition: LocalExtrapolatorCache.h:103
Trk::AlignableTrackingVolume::binnedMaterial
const BinnedMaterial * binnedMaterial() const
access to binned material
Definition: AlignableTrackingVolume.h:68
TrkExTools::possibleToolNameError
std::string possibleToolNameError(const std::vector< std::string > &toolNameVector)
Give an error message if tool names are invalid; empty string if good.
Definition: TrkExToolsStringUtility.cxx:34
Trk::NumberOfSignatures
@ NumberOfSignatures
Definition: GeometrySignature.h:32
Trk::BoundarySurfaceFace
BoundarySurfaceFace
Definition: BoundarySurfaceFace.h:31
python.SystemOfUnits.millimeter
float millimeter
Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration # This software is distribute...
Definition: SystemOfUnits.py:62
Trk::ParametersNextVolume::navParameters
Trk::TrackParameters * navParameters
Definition: ParametersNextVolume.h:18
Trk::Layer::layerType
int layerType() const
get the Layer coding
Trk::Extrapolator::extrapolateToVolume
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 :
Definition: Extrapolator.cxx:588
Trk::Cache::addOneNavigationLayer
void addOneNavigationLayer(const Trk::TrackingVolume *pDetVol, const Trk::Layer *pLayer, bool boundaryCheck=true)
Add one layer and navigLayer.
Definition: LocalExtrapolatorCache.cxx:128
Trk::Cache::kRecursionCountExceeded
@ kRecursionCountExceeded
Definition: LocalExtrapolatorCache.h:103
Trk::Extrapolator::extrapolateToVolumeImpl
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.
Definition: Extrapolator.cxx:1998
Trk::Layer::preUpdateMaterialFactor
virtual double preUpdateMaterialFactor(const TrackParameters &, PropDirection) const
getting the MaterialProperties back - for pre-update
Definition: Layer.h:144
ExtrapolationCache.h
Trk::Surface::baseSurface
virtual const Trk::Surface * baseSurface() const
return the base surface (simplified for persistification)
Track.h
Trk::MS
@ MS
Definition: GeometrySignature.h:29
Trk::TrackingVolume::confinedLayers
const LayerArray * confinedLayers() const
Return the subLayer array.
Trk::Layer::surfaceArray
const SurfaceArray * surfaceArray() const
Return the entire SurfaceArray, returns nullptr if no SurfaceArray.
Trk::FastField
@ FastField
call the fast field access method of the FieldSvc
Definition: MagneticFieldMode.h:20
Trk::Extrapolator::extrapolateDirectly
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.
Definition: Extrapolator.cxx:346
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:28
GeoPrimitives.h
SurfaceBounds.h
Trk::MaterialEffectsOnTrack
represents the full description of deflection and e-loss of a track in material.
Definition: MaterialEffectsOnTrack.h:40
Trk::Layer::subSurface
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
Volume.h
Trk::Cache::m_boundaryVolume
const Volume * m_boundaryVolume
Destination Surface for recall.
Definition: LocalExtrapolatorCache.h:54
Trk::PropDirection
PropDirection
Definition: PropDirection.h:19
Trk::Cache::subMaterialEffectsUpdatorCache
IMaterialEffectsUpdator::ICache & subMaterialEffectsUpdatorCache(const TrackingVolume &tvol)
Get the IMaterialEffectsUpdator::ICache for the MaterialEffectsUpdator.
Definition: LocalExtrapolatorCache.cxx:53
Trk::TrackingGeometry::highestTrackingVolume
const TrackingVolume * highestTrackingVolume() const
return the world
Trk::Surface::isOnSurface
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
Trk::Material::x0
float x0() const
Definition: Material.h:227
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
ParticleGun_EoverP_Config.mom
mom
Definition: ParticleGun_EoverP_Config.py:63
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
Trk::Layer::surfaceRepresentation
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
Trk::Extrapolator::extrapolateStepwiseImpl
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
Definition: Extrapolator.cxx:615
Trk::Cache::m_layerResolved
unsigned int m_layerResolved
Definition: LocalExtrapolatorCache.h:50
Trk::active
@ active
Definition: Layer.h:47
AthCheckedComponent
Mixin class to perform additional checks on a component.
Definition: AthCheckedComponent.h:25
lumiFormat.i
int i
Definition: lumiFormat.py:85
Trk::Extrapolator::extrapolateToIntermediateLayer
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.
Definition: Extrapolator.cxx:3448
Trk::ArraySpan
std::span< T > ArraySpan
Definition: TrackingVolume.h:59
Trk::Cache::m_matstates
std::vector< const Trk::TrackStateOnSurface * > * m_matstates
Definition: LocalExtrapolatorCache.h:79
beamspotman.n
n
Definition: beamspotman.py:727
Trk::TrackingVolume::confinedArbitraryLayers
ArraySpan< Layer const *const > confinedArbitraryLayers() const
Return the confined subLayer array.
Trk::theta
@ theta
Definition: ParamDefs.h:66
Trk::IPropagator
Definition: IPropagator.h:55
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
Trk::ParametersNextVolume::boundaryInformation
void boundaryInformation(const TrackingVolume *tvol, Trk::TrackParameters *nextPars, Trk::TrackParameters *navPars, BoundarySurfaceFace face=undefinedFace)
reset the boundary information by invalidating it
Definition: ParametersNextVolume.h:29
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Trk::Extrapolator::extrapolateInAlignableTV
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
Definition: Extrapolator.cxx:1742
TrkExToolsStringUtility.h
namespaced string utilities for TrkExTools
Trk::Cache::m_denseResolved
std::pair< unsigned int, unsigned int > m_denseResolved
Definition: LocalExtrapolatorCache.h:83
Trk::TrackingVolume::confinedDenseVolumes
ArraySpan< TrackingVolume const *const > confinedDenseVolumes() const
Return unordered subVolumes - not the ownership.
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
Trk::DistanceSolution::second
double second() const
Distance to second intersection solution along direction (for a cylinder surface)
Trk::Cache::m_dense
bool m_dense
Definition: LocalExtrapolatorCache.h:49
Trk::Extrapolator::radialDirectionCheck
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...
Definition: Extrapolator.cxx:3906
Trk::TrackingGeometry::lowestStaticTrackingVolume
const TrackingVolume * lowestStaticTrackingVolume(const Amg::Vector3D &gp) const
return the lowest static tracking Volume
Definition: TrackingGeometry.cxx:72
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
Trk::Extrapolator::extrapolateToVolumeWithPathLimit
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
Definition: Extrapolator.cxx:4070
Trk::Extrapolator::identifiedParameters_t
std::vector< std::pair< std::unique_ptr< Trk::TrackParameters >, int > > identifiedParameters_t
Definition: Extrapolator.h:248
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
CylinderSurface.h
Trk::Cache::m_navigSurfs
std::vector< std::pair< const Trk::Surface *, Trk::BoundaryCheck > > m_navigSurfs
Definition: LocalExtrapolatorCache.h:94
Trk::EnergyLoss::deltaE
double deltaE() const
returns the
Trk::Cache::m_highestVolume
const Trk::TrackingVolume * m_highestVolume
Definition: LocalExtrapolatorCache.h:63
Trk::NavigationCell::exitFace
BoundarySurfaceFace exitFace
Definition: INavigator.h:43
Trk::Surface::normal
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
Trk::Layer::nextLayer
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
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Trk::Cache::m_staticBoundaries
std::vector< DestSurf > m_staticBoundaries
Definition: LocalExtrapolatorCache.h:85
CylinderLayer.h
Trk::Cache::m_denseBoundaries
std::vector< DestSurf > m_denseBoundaries
Definition: LocalExtrapolatorCache.h:87
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk::TrackingVolume::boundarySurfaces
std::vector< std::shared_ptr< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
Definition: TrackingVolume.cxx:809
Trk::Cache::m_recallSurface
const Surface * m_recallSurface
Destination Layer for recall.
Definition: LocalExtrapolatorCache.h:56
Trk::CurvilinearParametersT
Definition: CurvilinearParametersT.h:48
Trk::Cache::m_currentDense
const Trk::TrackingVolume * m_currentDense
Definition: LocalExtrapolatorCache.h:62
Trk::Cache::m_trackingGeometry
const Trk::TrackingGeometry * m_trackingGeometry
Definition: LocalExtrapolatorCache.h:65
DeMoUpdate.tmp
string tmp
Definition: DeMoUpdate.py:1167
Trk::neutron
@ neutron
Definition: ParticleHypothesis.h:36
Trk::Cache::m_recursionCount
std::array< unsigned short, kNRecursionValues > m_recursionCount
Definition: LocalExtrapolatorCache.h:101
Trk::Extrapolator::positionOutput
std::string positionOutput(const Amg::Vector3D &pos) const
For the output - global position.
Definition: Extrapolator.cxx:3952
Trk::TrackParametersUVector
std::vector< std::unique_ptr< Trk::TrackParameters > > TrackParametersUVector
Definition: Extrapolator.h:62
Trk::EnergyLoss::meanRad
double meanRad() const
dot.dot
def dot(G, fn, nodesToHighlight=[])
Definition: dot.py:5
Trk::LayerIndex::value
int value() const
layerIndex expressed in an integer
Definition: LayerIndex.h:71
Trk::BinnedArray::arrayObjects
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
Trk::FullField
@ FullField
Field is set to be realistic, but within a given Volume.
Definition: MagneticFieldMode.h:21
Trk::Cache::m_recallLayer
const Layer * m_recallLayer
Destination TrackingVolume for recall.
Definition: LocalExtrapolatorCache.h:58
DetachedTrackingVolume.h
beamspotman.dir
string dir
Definition: beamspotman.py:619
Trk::Extrapolator::extrapolateStepwise
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.
Definition: Extrapolator.cxx:401
Trk::IPropagator::propagateParameters
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.
Trk::Extrapolator::extrapolateFromLayerToLayer
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...
Definition: Extrapolator.cxx:3265
Trk::Global
@ Global
Definition: GeometrySignature.h:25
Trk::Track::trackParameters
const DataVector< const TrackParameters > * trackParameters() const
Return a pointer to a vector of TrackParameters.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:97
Trk::Cache::elossPointerErrorMsg
std::string elossPointerErrorMsg(int lineNumber=0) const
String error message if the cache has a problem.
Definition: LocalExtrapolatorCache.cxx:109
EventPrimitives.h
Trk::Cache::m_destinationSurface
const Surface * m_destinationSurface
the boundary volume check
Definition: LocalExtrapolatorCache.h:52
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::TrackingVolume::volumeName
const std::string & volumeName() const
Returns the VolumeName - for debug reason, might be depreciated later.
IMultipleScatteringUpdator.h
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
Trk::Extrapolator::extrapolateToDestinationLayer
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.
Definition: Extrapolator.cxx:3380
Trk::Surface::bounds
virtual const SurfaceBounds & bounds() const =0
Surface Bounds method.
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
Trk::Extrapolator::extrapolate
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.
Definition: Extrapolator.cxx:385
Trk::IMaterialEffectsUpdator::update
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...
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:28
Trk::EnergyLoss
This class describes energy loss material effects in the ATLAS tracking EDM.
Definition: EnergyLoss.h:34
BoundarySurfaceFace.h
AtlCoolConsole.tool
tool
Definition: AtlCoolConsole.py:452
Trk::DistanceSolution::absClosest
double absClosest() const
Absolute Distance to closest solution.
Trk::Extrapolator::extrapolateWithinDetachedVolumes
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.
Definition: Extrapolator.cxx:2678
Trk::IdentifiedMaterial
std::pair< std::shared_ptr< Material >, int > IdentifiedMaterial
Definition: BinnedMaterial.h:23
Trk::Extrapolator::extrapolateM
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.
Definition: Extrapolator.cxx:471
MaterialLayer.h
Trk::Layer::thickness
double thickness() const
Return the Thickness of the Layer.
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
Trk::ExtrapolationCache::updateEloss
void updateEloss(double ioni, double sigi, double rad, double sigr)
Trk::IMaterialEffectsUpdator::preUpdate
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...
Trk::Extrapolator::initializeNavigation
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...
Definition: Extrapolator.cxx:3717
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
BoundarySurface.h
Trk::NavigationCell
useful struct for a single navigation cell
Definition: INavigator.h:38
Trk::Extrapolator::initialize
virtual StatusCode initialize() override
AlgTool initailize method.
Definition: Extrapolator.cxx:131
Trk::Surface::associatedLayer
const Trk::Layer * associatedLayer() const
return the associated Layer
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
Trk::IMaterialEffectsUpdator::postUpdate
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...
DeMoScan.index
string index
Definition: DeMoScan.py:362
Trk::MaterialProperties
Definition: MaterialProperties.h:40
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
Trk::Cache::m_methodSequence
unsigned int m_methodSequence
Definition: LocalExtrapolatorCache.h:51
Trk::ExtrapolationCache::x0tot
double x0tot() const
Trk::IPropagator::propagate
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.
mapkey::sf
@ sf
Definition: TElectronEfficiencyCorrectionTool.cxx:38
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::TrackingGeometry::lowestDetachedTrackingVolumes
std::vector< const Trk::DetachedTrackingVolume * > lowestDetachedTrackingVolumes(const Amg::Vector3D &gp) const
return the vector of lowest detached tracking Volume(->overlaps)
Definition: TrackingGeometry.cxx:60
TRT_PAI_physicsConstants::mb
const double mb
1mb to cm2
Definition: TRT_PAI_physicsConstants.h:17
Trk::userOwn
@ userOwn
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:61
Trk::BoundaryCheck
Definition: BoundaryCheck.h:51
Trk::BinnedMaterial::material
const IdentifiedMaterial * material(const Amg::Vector3D &position) const
access to material/id per bin
Definition: BinnedMaterial.cxx:58
Trk::addNoise
@ addNoise
Definition: MaterialUpdateMode.h:19
PlaneSurface.h
Trk::TrackingVolume::confinedVolumes
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
Trk::Extrapolator::extrapolateToNextMaterialLayer
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
Definition: Extrapolator.cxx:726
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
Trk::Cache::elossPointerOverwritten
bool elossPointerOverwritten() const
Check cache integrity.
Definition: LocalExtrapolatorCache.cxx:104
Trk::Layer::enclosingTrackingVolume
const TrackingVolume * enclosingTrackingVolume() const
get the confining TrackingVolume
Trk::SurfaceType::Cylinder
@ Cylinder
Trk::Extrapolator::Extrapolator
Extrapolator(const std::string &, const std::string &, const IInterface *)
Constructor.
Definition: Extrapolator.cxx:116
Trk::Layer::layerMaterialProperties
const LayerMaterialProperties * layerMaterialProperties() const
getting the LayerMaterialProperties including full/pre/post update
Trk::TrackingGeometry::trackingVolume
const TrackingVolume * trackingVolume(const std::string &name) const
return the tracking Volume by name, 0 if it doesn't exist
Trk::IMaterialEffectsUpdator
Definition: IMaterialEffectsUpdator.h:45
Trig::FeatureAccessImpl::collect
void collect(const HLT::TriggerElement *te, std::vector< Trig::Feature< T > > &data, const std::string &label, unsigned int condition, const std::string &teName, const HLT::TrigNavStructure *navstructure)
actual feature acceess implementation It has (thanks to the ClassTraits) functionality to flatten con...
Definition: FeatureCollectAthena.h:299
Trk::Extrapolator::extrapolateToVolumeBoundary
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.
Definition: Extrapolator.cxx:2851
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
Trk::TrackingVolume::isAlignable
virtual bool isAlignable() const
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
Trk::Cache::to_string
std::string to_string(const std::string &txt) const
String representation of cache.
Definition: LocalExtrapolatorCache.cxx:86
MuonHough::extrapolate
float extrapolate(const MuonLayerHough::Maximum &ref, const MuonLayerHough::Maximum &ex, bool doparabolic=false)
Definition: MuonLayerHough.cxx:521
Trk::Cache::copyToNavigationSurfaces
void copyToNavigationSurfaces()
Insert navigation surfaces from layers, dense boundaries, navig boundaries and detached boundaries.
Definition: LocalExtrapolatorCache.cxx:140
TrackingGeometry.h
Trk::Cache::kCurrentRecursionCount
@ kCurrentRecursionCount
Definition: LocalExtrapolatorCache.h:100
Trk::undefinedFace
@ undefinedFace
Definition: BoundarySurfaceFace.h:59
SubtractedCylinderLayer.h
Trk::tubeInnerCover
@ tubeInnerCover
Definition: BoundarySurfaceFace.h:39
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:13
Trk::CacheOwnedPtr
T * CacheOwnedPtr
Definition: ExtrUniquePtrHolder.h:28
Trk::ComparisonFunction< TrackParameters >
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
AthAlgTool
Definition: AthAlgTool.h:26
Trk::Cache::m_navigVolsInt
std::vector< std::pair< const Trk::TrackingVolume *, unsigned int > > m_navigVolsInt
Definition: LocalExtrapolatorCache.h:96
Trk::Cache::m_cacheLastMatLayer
bool m_cacheLastMatLayer
Definition: LocalExtrapolatorCache.h:72
Trk::TrackingGeometry::associatedLayer
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Forward the associated Layer information.
Trk::Extrapolator::extrapolateInsideVolume
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.
Definition: Extrapolator.cxx:2655
test_pyathena.counter
counter
Definition: test_pyathena.py:15
Trk::Cache::volume
const Trk::TrackingVolume * volume(const EventContext &, const Amg::Vector3D &gp) const
Definition: LocalExtrapolatorCache.h:117
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:79
Trk::Extrapolator::extrapolateTrack
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.
Definition: Extrapolator.cxx:422
Trk::Volume
Definition: Volume.h:36
Trk::Extrapolator::extrapolateToNextActiveLayerM
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.
Definition: Extrapolator.cxx:563
Trk::TrackingVolume
Definition: TrackingVolume.h:119
Trk::TrackingVolume::associatedLayer
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Return the associated Layer.
Definition: TrackingVolume.cxx:382
AlignableTrackingVolume.h
Trk::Extrapolator::extrapolateToNextActiveLayerMImpl
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.
Definition: Extrapolator.cxx:652
Trk::ExtrapolationCache
Definition: ExtrapolationCache.h:26
Trk::Cache::m_cacheEloss
const Trk::EnergyLoss * m_cacheEloss
cache of TrackStateOnSurfaces
Definition: LocalExtrapolatorCache.h:77
Trk::Surface::type
constexpr virtual SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
Trk::Cache::m_lastMaterialLayer
const Layer * m_lastMaterialLayer
cache for collecting the total X0 ans Eloss
Definition: LocalExtrapolatorCache.h:73
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
Trk::Cache::m_status
enum Trk::Cache::EStatus m_status
Trk::Cache::m_currentStatic
const Trk::TrackingVolume * m_currentStatic
Definition: LocalExtrapolatorCache.h:61
Trk::Extrapolator::extrapolateBlindly
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.
Definition: Extrapolator.cxx:447
TrackStateOnSurface.h
Trk::Cache::m_parametersAtBoundary
ParametersNextVolume m_parametersAtBoundary
Caches per MaterialUpdator.
Definition: LocalExtrapolatorCache.h:45
Extrapolator.h
Trk::Cache::m_identifiedParameters
std::unique_ptr< identifiedParameters_t > m_identifiedParameters
Definition: LocalExtrapolatorCache.h:81
Trk::ExtrapolationCache::eloss
const EnergyLoss * eloss() const
Trk::ParametersNextVolume::exitFace
BoundarySurfaceFace exitFace
Definition: ParametersNextVolume.h:19
Trk::EnergyLoss::sigmaIoni
double sigmaIoni() const
Trk::Layer
Definition: Layer.h:72
Trk::Cache::setTrackingGeometry
void setTrackingGeometry(const Trk::INavigator &navigator, const EventContext &ctx)
Definition: LocalExtrapolatorCache.h:110
Trk::Cache::m_nPropagations
unsigned int m_nPropagations
Definition: LocalExtrapolatorCache.h:102
Trk::AlignableTrackingVolume
Definition: AlignableTrackingVolume.h:36
Trk::Layer::layerIndex
const LayerIndex & layerIndex() const
get the layerIndex
TrkParametersComparisonFunction.h
Trk::SurfaceBounds::r
virtual double r() const =0
Interface method for the maximal extension or the radius.