ATLAS Offline Software
Loading...
Searching...
No Matches
TimedExtrapolator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6// TimedExtrapolator.cxx, (c) ATLAS Detector software
8
9#include "GaudiKernel/MsgStream.h"
10#include "GaudiKernel/PhysicalConstants.h"
11// Trk include
21#include "TrkTrack/Track.h"
24#include "TrkGeometry/Layer.h"
33#include "TrkVolumes/Volume.h"
43
44// for the comparison with a pointer
45#include <cstdint>
46
47// Amg
50
51// Trk
53
54
55// constructor
56Trk::TimedExtrapolator::TimedExtrapolator(const std::string &t, const std::string &n, const IInterface *p) :
57 AthAlgTool(t, n, p),
60 declareInterface<ITimedExtrapolator>(this);
61}
62
63// destructor
65
66// Athena standard methods
67// initialize
68StatusCode
72 if (m_propagators.empty()) {
73 m_propagators.push_back("Trk::RungeKuttaPropagator/DefaultPropagator");
74 }
75 if (m_updators.empty()) {
76 m_updators.push_back("Trk::MaterialEffectsUpdator/DefaultMaterialEffectsUpdator");
77 }
78 if (m_msupdators.empty()) {
79 m_msupdators.push_back("Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator");
80 }
81
82
83 if (!m_propagators.empty()) {
84 if (m_propagators.retrieve().isFailure()) {
85 ATH_MSG_FATAL("Failed to retrieve tool " << m_propagators);
86 return StatusCode::FAILURE;
87 }
88 ATH_MSG_INFO("Retrieved tools " << m_propagators);
89
90 }
91
92
93 // from the number of retrieved propagators set the configurationLevel
94 unsigned int validprop = m_propagators.size();
95
96 if (!validprop) {
97 ATH_MSG_WARNING("None of the defined propagators could be retrieved!");
98 ATH_MSG_WARNING(" Extrapolators jumps back in unconfigured mode, only strategy pattern methods can be used.");
99 } else {
100 m_configurationLevel = validprop - 1;
101 ATH_MSG_VERBOSE("Configuration level automatically set to " << m_configurationLevel);
102 }
103
104 // Get the Navigation AlgTools
105 if (m_navigator.retrieve().isFailure()) {
106 ATH_MSG_FATAL("Failed to retrieve tool " << m_navigator);
107 return StatusCode::FAILURE;
108 }
109 ATH_MSG_INFO("Retrieved tool " << m_navigator);
110
111 // Get the Material Updator
112 if (m_includeMaterialEffects && !m_updators.empty()) {
113 if (m_updators.retrieve().isFailure()) {
114 ATH_MSG_FATAL("None of the defined material updatros could be retrieved!");
115 ATH_MSG_FATAL("No multiple scattering and energy loss material update will be done.");
116 return StatusCode::FAILURE;
117 }
118 ATH_MSG_INFO("Retrieved tools: " << m_updators);
119
120 }
121
122 // from the number of retrieved propagators set the configurationLevel
123 unsigned int validmeuts = m_updators.size();
124
125 // -----------------------------------------------------------
126 // Sanity check 1
127
128 if (m_propNames.empty() && !m_propagators.empty()) {
129 ATH_MSG_DEBUG("Inconsistent setup of Extrapolator, no sub-propagators configured, doing it for you. ");
130 m_propNames.value().push_back(m_propagators[0]->name().substr(8, m_propagators[0]->name().size() - 8));
131 }
132
133 if (m_updatNames.empty() && !m_updators.empty()) {
134 ATH_MSG_DEBUG("Inconsistent setup of Extrapolator, no sub-materialupdators configured, doing it for you. ");
135 m_updatNames.value().push_back(m_updators[0]->name().substr(8, m_updators[0]->name().size() - 8));
136 }
137
138 // -----------------------------------------------------------
139 // Sanity check 2
140 // fill the number of propagator names and updator names up with first one
141 while (int(m_propNames.size()) < int(Trk::NumberOfSignatures)) {
142 m_propNames.value().push_back(m_propNames[0]);
143 }
144 while (int(m_updatNames.size()) < int(Trk::NumberOfSignatures)) {
145 m_updatNames.value().push_back(m_updatNames[0]);
146 }
147 if (validprop && validmeuts) {
148 // Per definition: if configured not found, take the lowest one
149 for (unsigned int isign = 0; int(isign) < int(Trk::NumberOfSignatures); ++isign) {
150 unsigned int index = 0;
151
152 for (unsigned int iProp = 0; iProp < m_propagators.size(); iProp++) {
153 std::string pname = m_propagators[iProp]->name().substr(8, m_propagators[iProp]->name().size() - 8);
154 if (m_propNames[isign] == pname) {
155 index = iProp;
156 }
157 }
158 ATH_MSG_DEBUG(" subPropagator:" << isign << " pointing to propagator: " << m_propagators[index]->name());
159 m_subPropagators[isign] = (index < validprop) ? &(*m_propagators[index]) : &(*m_propagators[Trk::Global]);
160
161 index = 0;
162 for (unsigned int iUp = 0; iUp < m_updators.size(); iUp++) {
163 std::string uname = m_updators[iUp]->name().substr(8, m_updators[iUp]->name().size() - 8);
164 if (m_updatNames[isign] == uname) {
165 index = iUp;
166 }
167 }
168 ATH_MSG_DEBUG(" subMEUpdator:" << isign << " pointing to updator: " << m_updators[index]->name());
169 m_subUpdators[isign] = (index < validmeuts) ? &(*m_updators[index]) : &(*m_updators[Trk::Global]);
170 }
171 } else {
172 ATH_MSG_FATAL("Configuration Problem of Extrapolator: "
173 << " -- At least one IPropagator and IMaterialUpdator instance have to be given.! ");
174 }
175
176
177 m_maxNavigSurf = 1000;
178 m_maxNavigVol = 50;
179
180
181 ATH_MSG_INFO("initialize() successful");
182 return StatusCode::SUCCESS;
183}
184
185// finalize
186StatusCode
188 ATH_MSG_INFO("finalize() successful");
189 return StatusCode::SUCCESS;
190}
191
192std::unique_ptr<const Trk::TrackParameters>
194 const Trk::TrackParameters &parm,
195 Trk::PathLimit &pathLim, Trk::TimeLimit &timeLim,
198 std::vector<Trk::HitInfo> * &hitInfo,
199 Trk::GeometrySignature &nextGeoID,
200 const Trk::TrackingVolume *boundaryVol) const {
201// extrapolation method intended for simulation of particle decay; collects intersections with active layers
202// possible outcomes:1/ returns curvilinear parameters after reaching the maximal path
203// 2/ returns parameters at destination volume boundary
204// 3/ returns 0 ( particle stopped ) but keeps vector of hits
205
208 "M-[" << ++cache.m_methodSequence << "] extrapolateWithPathLimit(...) " << pathLim.x0Max << ", from " << parm.position());
210 "M-[" << ++cache.m_methodSequence << "] extrapolateWithPathLimit(...): resolve active layers? " << m_resolveActive);
211
212 if (!m_stepPropagator) {
213 // Get the STEP_Propagator AlgTool
214 if (m_stepPropagator.retrieve().isFailure()) {
215 ATH_MSG_ERROR("Failed to retrieve tool " << m_stepPropagator);
216 ATH_MSG_ERROR("Configure STEP Propagator for extrapolation with path limit");
217 return nullptr;
218 }
219 ATH_MSG_INFO("Retrieved tool " << m_stepPropagator);
220
221 }
222
223 // reset the path ( in x0 !!)
224 cache.m_path = PathLimit(pathLim.x0Max - pathLim.x0Collected, pathLim.process); // collect material locally
225
226 // initialize hit vector
227 cache.m_hitVector = hitInfo;
228
229 // if no input volume, define as highest volume
230 // const Trk::TrackingVolume* destVolume = boundaryVol ? boundaryVol : m_navigator->highestVolume();
231 cache.m_currentStatic = nullptr;
232 if (boundaryVol && !boundaryVol->inside(parm.position(), m_tolerance)) {
233 return nullptr;
234 }
235
236 // extrapolate to destination volume boundary with path limit
237 std::unique_ptr<const Trk::TrackParameters> returnParms =
239 cache, parm, timeLim, dir, particle, nextGeoID, boundaryVol);
240
241 // save actual path on output
242 if (cache.m_path.x0Collected > 0.) {
243 pathLim.updateMat(cache.m_path.x0Collected, cache.m_path.weightedZ / cache.m_path.x0Collected, cache.m_path.l0Collected);
244 }
245
246 if (hitInfo) {
247 ATH_MSG_DEBUG(hitInfo->size() << " identified intersections found");
248 for (auto & ih : *hitInfo) {
249 ATH_MSG_DEBUG("R,z,ID:" << ih.trackParms->position().perp() << ","
250 << ih.trackParms->position().z() << ","
251 << ih.detID);
252 }
253 }
254
255 std::map<const Trk::TrackParameters *, bool>::iterator garbageIter = cache.m_garbageBin.begin();
256 std::map<const Trk::TrackParameters *, bool>::iterator garbageEnd = cache.m_garbageBin.end();
257 for (; garbageIter != garbageEnd; ++garbageIter) if (garbageIter->first) {
258 if(garbageIter->first == returnParms.get()) {
259 auto ret=returnParms->uniqueClone();
260 ATH_MSG_DEBUG(" [+] garbage - at "
261 << positionOutput(garbageIter->first->position())
262 << " parm=" << garbageIter->first
263 << " is the return param. Cloning to" << ret.get());
264 returnParms = std::move(ret);
265 }
266 }
267
268 return returnParms;
269}
270
271std::unique_ptr<const Trk::TrackParameters>
274 const Trk::TrackParameters &parm,
275 Trk::TimeLimit &timeLim,
278 Trk::GeometrySignature &nextGeoID,
279 const Trk::TrackingVolume *destVol) const {
280 // returns:
281 // A) curvilinear track parameters if path limit reached
282 // B) boundary parameters (at destination volume boundary)
283
284 // initialize the return parameters vector
285 std::unique_ptr<const Trk::TrackParameters> returnParameters = nullptr;
286 const Trk::TrackParameters *currPar = &parm;
287 const Trk::TrackingVolume *currVol = nullptr;
288 const Trk::TrackingVolume *nextVol = nullptr;
289 std::vector<unsigned int> solutions;
290 const Trk::TrackingVolume *assocVol = nullptr;
291 unsigned int iDest = 0;
292 const EventContext& ctx = Gaudi::Hive::currentContext();
293 ATH_MSG_DEBUG(" [+] start extrapolateToVolumeWithPathLimit - at " << positionOutput(parm.position())<<" parm="<<&parm);
294 // destination volume boundary ?
295 if (destVol && m_navigator->atVolumeBoundary(currPar, destVol, dir, nextVol, m_tolerance) && nextVol != destVol) {
296 return parm.uniqueClone();
297 }
298
299 if (!cache.m_highestVolume) {
300 cache.m_highestVolume = m_navigator->highestVolume(ctx);
301 }
302
303 emptyGarbageBin(cache,&parm);
304 // navigation surfaces
305 if (cache.m_navigSurfs.capacity() > m_maxNavigSurf) {
306 cache.m_navigSurfs.reserve(m_maxNavigSurf);
307 }
308 cache.m_navigSurfs.clear();
309
310 // target volume may not be part of tracking geometry
311 if (destVol) {
312 const Trk::TrackingVolume *tgVol = m_navigator->trackingGeometry(ctx)->trackingVolume(destVol->volumeName());
313 if (!tgVol || tgVol != destVol) {
314 const auto & bounds = destVol->boundarySurfaces();
315 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
316 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
317 cache.m_navigSurfs.emplace_back(&surf, true);
318 }
319 iDest = bounds.size();
320 }
321 }
322
323 // resolve current position
324 bool updateStatic = false;
325 Amg::Vector3D gp = parm.position();
326
327 if (!cache.m_currentStatic || !cache.m_currentStatic->inside(gp, m_tolerance)) {
328 cache.m_currentStatic = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(gp);
329 updateStatic = true;
330 }
331 if (m_navigator->atVolumeBoundary(currPar, cache.m_currentStatic, dir, nextVol,
332 m_tolerance) && nextVol != cache.m_currentStatic) {
333 // no next volume found --- end of the world
334 if (!nextVol) {
335 ATH_MSG_DEBUG(" [+] Word boundary reached - at " << positionOutput(currPar->position()));
337 return currPar->uniqueClone();
338 }
339 cache.m_currentStatic = nextVol;
340 updateStatic = true;
341 }
342
343 // current frame volume known-retrieve geoID
344 nextGeoID = cache.m_currentStatic->geometrySignature();
345
346 // resolve active Calo volumes if hit info required
347 if (cache.m_hitVector && nextGeoID == Trk::Calo) {
348 const Trk::AlignableTrackingVolume *alignTV = dynamic_cast<const Trk::AlignableTrackingVolume *> (cache.m_currentStatic);
349 if (alignTV) {
350 Trk::BoundaryTrackParameters boundPar = extrapolateInAlignableTV(cache,*currPar, timeLim, dir, particle, nextGeoID,
351 alignTV);
352 const Trk::TrackParameters *aPar = boundPar.trPar;
353 if (!aPar) {
354 return returnParameters;
355 }
357 // cache.m_currentStatic = boundPar.exitVol;
358 return extrapolateToVolumeWithPathLimit(cache,*aPar, timeLim, dir, particle, nextGeoID, destVol);
359 }
360 }
361
362 // update if new static volume
363 if (updateStatic) { // retrieve boundaries
364 cache.m_staticBoundaries.clear();
365 const auto& bounds = cache.m_currentStatic->boundarySurfaces();
366 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
367 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
368 cache.m_staticBoundaries.emplace_back(&surf, true);
369 }
370
371 cache.m_detachedVols.clear();
372 cache.m_detachedBoundaries.clear();
373 cache.m_denseVols.clear();
374 cache.m_denseBoundaries.clear();
375 cache.m_layers.clear();
376 cache.m_navigLays.clear();
377
378 // new: ID volumes may have special material layers ( entry layers ) - add them here
379 // if (cache.m_currentStatic->entryLayerProvider()) {
380 // const std::vector<const Trk::Layer*>& entryLays = cache.m_currentStatic->entryLayerProvider()->layers();
381 // for (unsigned int i=0; i < entryLays.size(); i++) {
382 // if (entryLays[i]->layerType()>0 || entryLays[i]->layerMaterialProperties()) {
383 // cache.m_layers.push_back(std::pair<const
384 // Trk::Surface*,Trk::BoundaryCheck>(&(entryLays[i]->surfaceRepresentation()),true));
385 // cache.m_navigLays.push_back(std::pair<const Trk::TrackingVolume*,const Trk::Layer*> (cache.m_currentStatic,entryLays[i])
386 // );
387 // Trk::DistanceSolution distSol = cache.m_layers.back().first->straightLineDistanceEstimate(currPar->position(),
388 //
389 //
390 //
391 // currPar->momentum().normalized());
392 // }
393 // }
394 // }
395
396 // detached volume boundaries
397 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const> detVols = cache.m_currentStatic->confinedDetachedVolumes();
398 if (!detVols.empty()) {
399 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const>::iterator iTer = detVols.begin();
400 for (; iTer != detVols.end(); ++iTer) {
401 // active station ?
402 const Trk::Layer *layR = (*iTer)->layerRepresentation();
403 bool active = layR && layR->layerType();
404 const auto& detBounds = (*iTer)->trackingVolume()->boundarySurfaces();
405 if (active) {
406 cache.m_detachedVols.emplace_back(*iTer,
407 detBounds.size());
408 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
409 const Trk::Surface &surf = (detBounds[ibb])->surfaceRepresentation();
410 cache.m_detachedBoundaries.emplace_back(&surf, true);
411 }
412 } else if (cache.m_currentStatic->geometrySignature() != Trk::MS ||
414 (*iTer)->name().substr((*iTer)->name().size() - 4, 4) ==
415 "PERM") { // retrieve
416 // inert
417 // detached
418 // objects
419 // only if
420 // needed
421 if ((*iTer)->trackingVolume()->zOverAtimesRho() != 0. &&
422 ((*iTer)->trackingVolume()->confinedDenseVolumes().empty())
423 && (*iTer)->trackingVolume()->confinedArbitraryLayers().empty()) {
424 cache.m_denseVols.emplace_back((*iTer)->trackingVolume(), detBounds.size());
425 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
426 const Trk::Surface &surf = (detBounds[ibb])->surfaceRepresentation();
427 cache.m_denseBoundaries.emplace_back(&surf, true);
428 }
429 }
430 Trk::ArraySpan<const Trk::Layer* const> confLays = (*iTer)->trackingVolume()->confinedArbitraryLayers();
431 if (!(*iTer)->trackingVolume()->confinedDenseVolumes().empty() || (confLays.size() > detBounds.size())) {
432 cache.m_detachedVols.emplace_back(*iTer, detBounds.size());
433 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
434 const Trk::Surface &surf = (detBounds[ibb])->surfaceRepresentation();
435 cache.m_detachedBoundaries.emplace_back(&surf, true);
436 }
437 } else if (!confLays.empty()) {
438 for (const Trk::Layer* const lIt : confLays) {
439 cache.m_layers.emplace_back(&(lIt->surfaceRepresentation()),
440 true);
441 cache.m_navigLays.emplace_back((*iTer)->trackingVolume(), lIt);
442 }
443 }
444 }
445 }
446 }
447 cache.m_denseResolved = std::pair<unsigned int, unsigned int> (cache.m_denseVols.size(), cache.m_denseBoundaries.size());
448 cache.m_layerResolved = cache.m_layers.size();
449 }
450
451 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_staticBoundaries.begin(), cache.m_staticBoundaries.end());
452
453 // resolve the use of dense volumes
454 cache.m_dense = (cache.m_currentStatic->geometrySignature() == Trk::MS && m_useMuonMatApprox) ||
455 (cache.m_currentStatic->geometrySignature() != Trk::MS && m_useDenseVolumeDescription);
456
457 // reset remaining counters
458 cache.m_currentDense = cache.m_dense ? cache.m_currentStatic : cache.m_highestVolume;
459 cache.m_navigBoundaries.clear();
460 if (cache.m_denseVols.size() > cache.m_denseResolved.first) {
461 cache.m_denseVols.resize(cache.m_denseResolved.first);
462 }
463 while (cache.m_denseBoundaries.size() > cache.m_denseResolved.second) {
464 cache.m_denseBoundaries.pop_back();
465 }
466 if (cache.m_layers.size() > cache.m_layerResolved) {
467 cache.m_navigLays.resize(cache.m_layerResolved);
468 }
469 while (cache.m_layers.size() > cache.m_layerResolved) {
470 cache.m_layers.pop_back();
471 }
472
473 // current detached volumes
474 // collect : subvolume boundaries, ordered/unordered layers, confined dense volumes
476 // const Trk::DetachedTrackingVolume* currentActive = 0;
477 std::vector<std::pair<const Trk::TrackingVolume *, unsigned int> > navigVols;
478
479 gp = currPar->position();
480 std::vector<const Trk::DetachedTrackingVolume *> detVols =
481 m_navigator->trackingGeometry(ctx)->lowestDetachedTrackingVolumes(gp);
482 std::vector<const Trk::DetachedTrackingVolume *>::iterator dIter = detVols.begin();
483 for (; dIter != detVols.end(); ++dIter) {
484 const Trk::Layer *layR = (*dIter)->layerRepresentation();
485 bool active = layR && layR->layerType();
486 if (active && !m_resolveActive) {
487 continue;
488 }
489 if (!active && cache.m_currentStatic->geometrySignature() == Trk::MS &&
490 m_useMuonMatApprox && (*dIter)->name().substr((*dIter)->name().size() - 4, 4) != "PERM") {
491 continue;
492 }
493 const Trk::TrackingVolume *dVol = (*dIter)->trackingVolume();
494 // detached volume exit ?
495 bool dExit = m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) && !nextVol;
496 if (dExit) {
497 continue;
498 }
499 // inert material
500 const auto& confinedDense = dVol->confinedDenseVolumes();
501 const auto& confinedLays = dVol->confinedArbitraryLayers();
502
503 if (!active && confinedDense.empty() && confinedLays.empty()) {
504 continue;
505 }
506 const auto &bounds = dVol->boundarySurfaces();
507 if (!active && confinedDense.empty() && confinedLays.size() <= bounds.size()) {
508 continue;
509 }
510 if (!confinedDense.empty() || !confinedLays.empty()) {
511 navigVols.emplace_back(dVol, bounds.size());
512 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
513 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
514 cache.m_navigBoundaries.emplace_back(&surf, true);
515 }
516 // collect dense volume boundary
517 if (!confinedDense.empty()) {
518 auto vIter = confinedDense.begin();
519 for (; vIter != confinedDense.end(); ++vIter) {
520 const auto& bounds = (*vIter)->boundarySurfaces();
521 cache.m_denseVols.emplace_back(*vIter, bounds.size());
522 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
523 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
524 cache.m_denseBoundaries.emplace_back(&surf, true);
525 }
526 }
527 }
528 // collect unordered layers
529 if (!confinedLays.empty()) {
530 for (const auto *confinedLay : confinedLays) {
531 cache.m_layers.emplace_back(&(confinedLay->surfaceRepresentation()), true);
532 cache.m_navigLays.emplace_back(dVol, confinedLay);
533 }
534 }
535 } else { // active material
536 const Trk::TrackingVolume *detVol = dVol->associatedSubVolume(gp);
537 if (!detVol && dVol->confinedVolumes()) {
538 std::span<Trk::TrackingVolume const * const> subvols = dVol->confinedVolumes()->arrayObjects();
539 for (const auto *subvol : subvols) {
540 if (subvol->inside(gp, m_tolerance)) {
541 detVol = subvol;
542 break;
543 }
544 }
545 }
546
547 if (!detVol) {
548 detVol = dVol;
549 }
550 bool vExit = m_navigator->atVolumeBoundary(currPar, detVol, dir, nextVol, m_tolerance) && nextVol != detVol;
551 if (vExit && nextVol && nextVol->inside(gp, m_tolerance)) {
552 detVol = nextVol;
553 vExit = false;
554 }
555 if (!vExit) {
556 const auto &bounds = detVol->boundarySurfaces();
557 navigVols.emplace_back(detVol, bounds.size());
558 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
559 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
560 cache.m_navigBoundaries.emplace_back(&surf, true);
561 }
562 if (detVol->zOverAtimesRho() != 0.) {
563 cache.m_denseVols.emplace_back(detVol, bounds.size());
564 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
565 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
566 cache.m_denseBoundaries.emplace_back(&surf, true);
567 }
568 }
569 // layers ?
570 if (detVol->confinedLayers()) {
571 if (m_robustSampling || cache.m_currentStatic->geometrySignature() == Trk::MS) {
572 std::span<Trk::Layer const * const> cLays = detVol->confinedLayers()->arrayObjects();
573 for (const auto *cLay : cLays) {
574 if (cLay->layerType() > 0 || cLay->layerMaterialProperties()) {
575 cache.m_layers.emplace_back(&(cLay->surfaceRepresentation()), true);
576 cache.m_navigLays.emplace_back(cache.m_currentStatic,
577 cLay);
578 }
579 }
580 } else {
581 const Trk::Layer *lay = detVol->associatedLayer(gp);
582 // if (lay && ( (*dIter)->layerRepresentation()
583 // &&(*dIter)->layerRepresentation()->layerType()>0 ) ) currentActive=(*dIter);
584 if (lay) {
585 cache.m_layers.emplace_back(&(lay->surfaceRepresentation()),
586 true);
587 cache.m_navigLays.emplace_back(detVol, lay);
588 }
589 const Trk::Layer *nextLayer = detVol->nextLayer(currPar->position(),
590 dir * currPar->momentum().normalized(), true);
591 if (nextLayer && nextLayer != lay) {
592 cache.m_layers.emplace_back(&(nextLayer->surfaceRepresentation()), true);
593 cache.m_navigLays.emplace_back(detVol, nextLayer);
594 }
595 }
596 } else if (!detVol->confinedArbitraryLayers().empty()) {
598 for (const auto *layer : layers) {
599 cache.m_layers.emplace_back(&(layer->surfaceRepresentation()), true);
600 cache.m_navigLays.emplace_back(detVol, layer);
601 }
602 }
603 }
604 }
605 }
606
607 // confined layers
608 if (cache.m_currentStatic->confinedLayers() && updateStatic) {
609 // if ( cache.m_currentStatic->confinedLayers() ) {
610 if (m_robustSampling || cache.m_currentStatic->geometrySignature() == Trk::MS) {
611 std::span<Trk::Layer const * const> cLays = cache.m_currentStatic->confinedLayers()->arrayObjects();
612 for (const auto *cLay : cLays) {
613 if (cLay->layerType() > 0 || cLay->layerMaterialProperties()) {
614 cache.m_layers.emplace_back(&(cLay->surfaceRepresentation()),
615 true);
616 cache.m_navigLays.emplace_back(cache.m_currentStatic, cLay);
617 }
618 }
619 } else {
620 // * this does not work - debug !
621 const Trk::Layer *lay = cache.m_currentStatic->associatedLayer(gp);
622 // if (!lay) {
623 // lay = cache.m_currentStatic->associatedLayer(gp+m_tolerance*parm.momentum().normalized());
624 // std::cout<<" find input associated layer, second attempt:"<< lay<< std::endl;
625 // }
626 if (lay) {
627 cache.m_layers.emplace_back(&(lay->surfaceRepresentation()),
628 Trk::BoundaryCheck(false));
629 cache.m_navigLays.emplace_back(cache.m_currentStatic, lay);
630 const Trk::Layer *nextLayer = lay->nextLayer(currPar->position(), dir * currPar->momentum().normalized());
631 if (nextLayer && nextLayer != lay) {
632 cache.m_layers.emplace_back(&(nextLayer->surfaceRepresentation()),
633 Trk::BoundaryCheck(false));
634 cache.m_navigLays.emplace_back(cache.m_currentStatic,
635 nextLayer);
636 }
637 const Trk::Layer *backLayer = lay->nextLayer(currPar->position(), -dir * currPar->momentum().normalized());
638 if (backLayer && backLayer != lay) {
639 cache.m_layers.emplace_back(&(backLayer->surfaceRepresentation()),
640 Trk::BoundaryCheck(false));
641 cache.m_navigLays.emplace_back(cache.m_currentStatic,
642 backLayer);
643 }
644 }
645 }
646 }
647
648 // cache.m_navigSurfs contains destination surface (if it exists), static volume boundaries
649 // complete with TG cache.m_layers/dynamic layers, cache.m_denseBoundaries, cache.m_navigBoundaries, m_detachedBoundaries
650
651 if (!cache.m_layers.empty()) {
652 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_layers.begin(), cache.m_layers.end());
653 }
654 if (!cache.m_denseBoundaries.empty()) {
655 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_denseBoundaries.begin(), cache.m_denseBoundaries.end());
656 }
657 if (!cache.m_navigBoundaries.empty()) {
658 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_navigBoundaries.begin(), cache.m_navigBoundaries.end());
659 }
660 if (!cache.m_detachedBoundaries.empty()) {
661 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_detachedBoundaries.begin(), cache.m_detachedBoundaries.end());
662 }
663
664
665 // current dense
666 cache.m_currentDense = cache.m_highestVolume;
667 if (cache.m_dense && cache.m_denseVols.empty()) {
668 cache.m_currentDense = cache.m_currentStatic;
669 } else {
670 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
671 const Trk::TrackingVolume *dVol = cache.m_denseVols[i].first;
672 if (dVol->inside(currPar->position(), m_tolerance) && dVol->zOverAtimesRho() != 0.) {
673 if (!m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) || nextVol == dVol) {
674 cache.m_currentDense = dVol;
675 }
676 }
677 }
678 }
679
680 // before propagation, loop over layers and collect hits
681 if (cache.m_hitVector) {
682 for (unsigned int i = 0; i < cache.m_navigLays.size(); i++) {
683 if (cache.m_navigLays[i].second->layerType() > 0 && cache.m_navigLays[i].second->isOnLayer(currPar->position())) {
684 if (cache.m_navigLays[i].second->surfaceArray()) {
685 // perform the overlap Search on this layer
686 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on input layer.");
687 overlapSearch(cache,*m_subPropagators[0], *currPar, *currPar, *cache.m_navigLays[i].second, timeLim.time, dir, true,
688 particle);
689 } else {
690 ATH_MSG_VERBOSE(" [o] Collecting intersection with active input layer.");
691 cache.m_hitVector->emplace_back(currPar->uniqueClone(), timeLim.time, cache.m_navigLays[i].second->layerType(), 0.);
692 }
693 } // ------------------------------------------------- Fatras mode off -----------------------------------
694 }
695 }
696
697 // ready to propagate
698 // till: A/ static volume boundary(bcheck=true) , B/ material layer(bcheck=true), C/ destination surface(bcheck=false)
699 // update of cache.m_navigSurfs required if I/ entry into new navig volume, II/ exit from currentActive without overlaps
700
701 nextVol = nullptr;
702 while (currPar) {
703 std::vector<unsigned int> solutions;
704 // double time_backup = timeLim.time;
705 // double path_backup = cache.m_path.x0Collected;
706 ATH_MSG_DEBUG(" [+] Starting propagation at position " << positionOutput(currPar->position())
707 << " (current momentum: " << currPar->momentum().mag() <<
708 ")");
709 ATH_MSG_DEBUG(" [+] " << cache.m_navigSurfs.size() << " target surfaces in '" << cache.m_currentDense->volumeName() << "'."); //
710 // verify
711 // that
712 // material
713 // input
714 // makes
715 // sense
716 if (!(cache.m_currentDense->inside(currPar->position(), m_tolerance)
717 || m_navigator->atVolumeBoundary(currPar, cache.m_currentDense, dir, assocVol, m_tolerance))) {
718 cache.m_currentDense = cache.m_highestVolume;
719 }
721 ->propagateT(ctx,
722 *currPar,
723 cache.m_navigSurfs,
724 dir,
726 particle,
727 solutions,
728 cache.m_path,
729 timeLim,
730 true,
731 cache.m_currentDense,
732 cache.m_hitVector)
733 .release();
734 ATH_MSG_VERBOSE(" [+] Propagation done. ");
735 if (nextPar) {
736 ATH_MSG_DEBUG(" [+] Position after propagation - at " << positionOutput(
737 nextPar->position()) << ", timed at " << timeLim.time);
738 }
739
740 if (!nextPar) {
741 ATH_MSG_DEBUG(" [!] Propagation failed, return 0");
742 cache.m_parametersAtBoundary.boundaryInformation(cache.m_currentStatic, nextPar, nextPar);
743 return returnParameters;
744 }
745
746 throwIntoGarbageBin(cache,nextPar);
747
748 // material update has been done already by the propagator
749 if (cache.m_path.x0Max > 0. &&
750 ((cache.m_path.process < 100 && cache.m_path.x0Collected >= cache.m_path.x0Max) ||
751 (cache.m_path.process > 100 && cache.m_path.l0Collected >= cache.m_path.x0Max))) {
752 // trigger presampled interaction, provide material properties if needed
753 // process interaction only if creation of secondaries allowed
754 if (cache.m_currentStatic->geometrySignature() == Trk::ID || m_caloMsSecondary) {
755 const Trk::Material *extMprop = cache.m_path.process > 100 ? cache.m_currentDense : nullptr;
756
757 const Trk::TrackParameters* iPar =
758 m_updators[0]
759 ->interact(
760 timeLim.time, nextPar->position(), nextPar->momentum(), particle, cache.m_path.process, extMprop)
761 .release();
762
763 if (!iPar) {
764 return returnParameters;
765 }
766
768 return extrapolateToVolumeWithPathLimit(cache,*iPar, timeLim, dir, particle, nextGeoID, destVol);
769 } // kill the particle without trace ( some validation info can be included here eventually )
770 return returnParameters;
771
772 }
773 // decay ?
774 if (timeLim.tMax > 0. && timeLim.time >= timeLim.tMax) {
775 // process interaction only if creation of secondaries allowed
776 if (cache.m_currentStatic->geometrySignature() == Trk::ID || m_caloMsSecondary) {
777 // trigger presampled interaction
778 const Trk::TrackParameters* iPar =
779 m_updators[0]
780 ->interact(timeLim.time, nextPar->position(), nextPar->momentum(), particle, timeLim.process)
781 .release();
782 if (!iPar) {
783 return returnParameters;
784 }
786 return extrapolateToVolumeWithPathLimit(cache,*iPar, timeLim, dir, particle, nextGeoID, destVol);
787 } // kill the particle without trace ( some validation info can be included here eventually )
788 return returnParameters;
789
790 }
791
792 // check missing volume boundary
793 if (nextPar && !(cache.m_currentDense->inside(nextPar->position(), m_tolerance)
794 || m_navigator->atVolumeBoundary(nextPar, cache.m_currentDense, dir, assocVol, m_tolerance))) {
795 ATH_MSG_DEBUG(" [!] ERROR: missing volume boundary for volume" << cache.m_currentDense->volumeName());
796 }
797
798
799 ATH_MSG_DEBUG(" [+] Number of intersection solutions: " << solutions.size());
800
801 unsigned int iSol = 0;
802 while (iSol < solutions.size()) {
803 if (solutions[iSol] < iDest) {
804 return nextPar->uniqueClone();
805 } if (solutions[iSol] < iDest + cache.m_staticBoundaries.size()) {
806 // material attached ?
807 const Trk::Layer *mb = cache.m_navigSurfs[solutions[iSol]].first->materialLayer();
808 if (mb && m_includeMaterialEffects) {
809 if (mb->layerMaterialProperties() && mb->layerMaterialProperties()->fullMaterial(nextPar->position())) {
810 const ITimedMatEffUpdator *currentUpdator = subMaterialEffectsUpdator(*cache.m_currentStatic);
811 nextPar = currentUpdator ? currentUpdator
812 ->update(nextPar,
813 *mb,
814 timeLim,
815 cache.m_path,
816 cache.m_currentStatic->geometrySignature(),
817 dir,
818 particle)
819 .release()
820 : nextPar;
821
822 if (!nextPar) {
823 ATH_MSG_VERBOSE(" [+] Update may have killed neutral track - return.");
824 cache.m_parametersAtBoundary.resetBoundaryInformation();
825 return returnParameters;
826 }
827 throwIntoGarbageBin(cache,nextPar);
828 } else { // material layer without material ?
829 ATH_MSG_VERBOSE(" boundary layer without material:" << mb->layerIndex());
830 }
831 }
832
833 // static volume boundary; return to the main loop
834 unsigned int index = solutions[iSol] - iDest;
835
836 // use global coordinates to retrieve attached volume (just for static!)
837 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
838 nextPar->position(), nextPar->momentum(), dir);
839 // double check the next volume
840 if (nextVol && !(nextVol->inside(nextPar->position() + 0.01 * dir * nextPar->momentum().normalized(), 0.))) {
842 " [!] WARNING: wrongly assigned static volume ?" << cache.m_currentStatic->volumeName() << "->" <<
843 nextVol->volumeName());
844 nextVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(
845 nextPar->position() + 0.01 * dir * nextPar->momentum().normalized());
846 if (nextVol) {
847 ATH_MSG_DEBUG(" new search yields: " << nextVol->volumeName());
848 }
849 }
850 // end double check - to be removed after validation of the geometry gluing
851 if (nextVol != cache.m_currentStatic) {
852 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
853 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '" << cache.m_currentStatic->volumeName() << "'.");
854 if (m_navigator->atVolumeBoundary(nextPar, cache.m_currentStatic, dir, assocVol,
855 m_tolerance) && assocVol != nextVol) {
856 cache.m_currentDense = cache.m_dense ? nextVol : cache.m_highestVolume;
857 }
858 // no next volume found --- end of the world
859 if (!nextVol) {
860 ATH_MSG_DEBUG(" [+] World boundary reached - at " << positionOutput(
861 nextPar->position()) << ", timed at " << timeLim.time);
863 if (!destVol) {
864 return nextPar->uniqueClone();
865 }
866 }
867 // next volume found and parameters are at boundary
868 if (nextVol /*&& nextPar nextPar is dereferenced anyway */) {
869 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
870 ATH_MSG_DEBUG(" [+] Crossing position is - at " << positionOutput(nextPar->position()));
871 if (!destVol && cache.m_currentStatic->geometrySignature() != nextVol->geometrySignature()) {
872 nextGeoID = nextVol->geometrySignature();
873 return nextPar->uniqueClone();
874 }
875 }
876 return extrapolateToVolumeWithPathLimit(cache,*nextPar, timeLim, dir, particle, nextGeoID, destVol);
877 }
878 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size()) {
879 // next layer; don't return passive material layers unless required
880 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size();
881 const Trk::Layer *nextLayer = cache.m_navigLays[index].second;
882 // material update ?
883 // bool matUp = nextLayer->layerMaterialProperties() && m_includeMaterialEffects &&
884 // nextLayer->isOnLayer(nextPar->position());
885 bool matUp = nextLayer->fullUpdateMaterialProperties(*nextPar) && m_includeMaterialEffects &&
886 nextLayer->isOnLayer(nextPar->position());
887 // material update
888 const ITimedMatEffUpdator *currentUpdator = subMaterialEffectsUpdator(*cache.m_currentStatic);
889 if (matUp) {
890 double pIn = nextPar->momentum().mag();
891 nextPar = currentUpdator ? currentUpdator->update(nextPar, *nextLayer, timeLim, cache.m_path,
892 cache.m_currentStatic->geometrySignature(), dir,
893 particle).release() : nextPar;
894 if (!nextPar) {
895 ATH_MSG_VERBOSE(" [+] Update may have killed track - return.");
896 cache.m_parametersAtBoundary.resetBoundaryInformation();
897 return returnParameters;
898 }
900 " Layer energy loss:" << nextPar->momentum().mag() - pIn << "at position:" << nextPar->position() << ", current momentum:" <<
901 nextPar->momentum());
902 throwIntoGarbageBin(cache,nextPar);
903
904 }
905 // active surface intersections ( Fatras hits ...)
906 if (cache.m_hitVector && particle != Trk::neutron) {
907 if (nextLayer->surfaceArray()) {
908 // perform the overlap Search on this layer
909 ATH_MSG_VERBOSE(" [o] Calling overlapSearch() on layer.");
910 overlapSearch(cache,*m_subPropagators[0], *currPar, *nextPar, *nextLayer, timeLim.time, dir, true, particle);
911 } else if (nextLayer->layerType() > 0 && nextLayer->isOnLayer(nextPar->position())) {
912 ATH_MSG_VERBOSE(" [o] Collecting intersection with active layer.");
913 cache.m_hitVector->emplace_back(nextPar->uniqueClone(), timeLim.time, nextLayer->layerType(), 0.);
914 }
915 } // ------------------------------------------------- Fatras mode off -----------------------------------
916
917 // TODO : debug the retrieval of next layer
918 if (!m_robustSampling && cache.m_currentStatic->geometrySignature() != Trk::MS) {
919 if (cache.m_navigLays[index].first && cache.m_navigLays[index].first->confinedLayers()) {
920 const Trk::Layer *newLayer = nextLayer->nextLayer(nextPar->position(),
921 dir * nextPar->momentum().normalized());
922 if (newLayer && newLayer != nextLayer) {
923 bool found = false;
924 int replace = -1;
925 for (unsigned int i = 0; i < cache.m_navigLays.size(); i++) {
926 if (cache.m_navigLays[i].second == newLayer) {
927 found = true;
928 break;
929 }
930 if (cache.m_navigLays[i].second != nextLayer) {
931 replace = i;
932 }
933 }
934 if (!found) {
935 if (replace > -1) {
936 cache.m_navigLays[replace].second = newLayer;
937 cache.m_navigSurfs[solutions[iSol] + replace - index].first = &(newLayer->surfaceRepresentation());
938 } else {
939 // can't insert a surface in middle
940 return extrapolateToVolumeWithPathLimit(cache,*nextPar, timeLim, dir, particle, nextGeoID, destVol);
941 }
942 }
943 }
944 }
945 }
946 currPar = nextPar;
947 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() + cache.m_denseBoundaries.size()) {
948 // dense volume boundary
949 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() - cache.m_layers.size();
950 std::vector< std::pair<const Trk::TrackingVolume *, unsigned int> >::iterator dIter = cache.m_denseVols.begin();
951 while (dIter != cache.m_denseVols.end() && index >= (*dIter).second) {
952 index -= (*dIter).second;
953 ++dIter;
954 }
955 if (dIter != cache.m_denseVols.end()) {
956 currVol = (*dIter).first;
957 nextVol = (currVol->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
958 // the boundary orientation is not reliable
959 Amg::Vector3D tp = nextPar->position() + 2 * m_tolerance * dir * nextPar->momentum().normalized();
960 if (!nextVol || !nextVol->inside(tp, m_tolerance)) { // search for dense volumes
961 cache.m_currentDense = cache.m_highestVolume;
962 if (cache.m_dense && cache.m_denseVols.empty()) {
963 cache.m_currentDense = cache.m_currentStatic;
964 } else {
965 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
966 const Trk::TrackingVolume *dVol = cache.m_denseVols[i].first;
967 if (dVol->inside(tp, m_tolerance) && dVol->zOverAtimesRho() != 0.) {
968 cache.m_currentDense = dVol;
969 ATH_MSG_DEBUG(" [+] Next dense volume found: '" << cache.m_currentDense->volumeName() << "'.");
970 break;
971 }
972 } // loop over dense volumes
973 }
974 } else {
975 cache.m_currentDense = nextVol;
976 ATH_MSG_DEBUG(" [+] Next dense volume: '" << cache.m_currentDense->volumeName() << "'.");
977 }
978 }
979 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() + cache.m_denseBoundaries.size()
980 + cache.m_navigBoundaries.size()) {
981 // navig volume boundary
982 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() - cache.m_layers.size() -
983 cache.m_denseBoundaries.size();
984 std::vector< std::pair<const Trk::TrackingVolume *, unsigned int> >::iterator nIter = navigVols.begin();
985 while (nIter != navigVols.end() && index >= (*nIter).second) {
986 index -= (*nIter).second;
987 ++nIter;
988 }
989 if (nIter != navigVols.end()) {
990 currVol = (*nIter).first;
991 nextVol = ((*nIter).first->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
992 if (!nextVol) {
993 ATH_MSG_DEBUG(" [+] Navigation volume boundary, leaving volume '"
994 << currVol->volumeName() << "'.");
995 } else {
996 ATH_MSG_DEBUG(" [+] Navigation volume boundary, entering volume '" << nextVol->volumeName() << "'.");
997 }
998 currPar = nextPar;
999 // return only if detached volume boundaries not collected
1000 // if ( nextVol || !detachedBoundariesIncluded )
1001 if (nextVol) {
1002 return extrapolateToVolumeWithPathLimit(cache,*currPar, timeLim, dir, particle, nextGeoID, destVol);
1003 }
1004 }
1005 } else if (solutions[iSol] < iDest + cache.m_staticBoundaries.size() + cache.m_layers.size() + cache.m_denseBoundaries.size()
1006 + cache.m_navigBoundaries.size() + cache.m_detachedBoundaries.size()) {
1007 // detached volume boundary
1008 unsigned int index = solutions[iSol] - iDest - cache.m_staticBoundaries.size() - cache.m_layers.size()
1009 - cache.m_denseBoundaries.size() - cache.m_navigBoundaries.size();
1010 std::vector< std::pair<const Trk::DetachedTrackingVolume *,
1011 unsigned int> >::iterator dIter = cache.m_detachedVols.begin();
1012 while (dIter != cache.m_detachedVols.end() && index >= (*dIter).second) {
1013 index -= (*dIter).second;
1014 ++dIter;
1015 }
1016 if (dIter != cache.m_detachedVols.end()) {
1017 currVol = (*dIter).first->trackingVolume();
1018 nextVol =
1019 ((*dIter).first->trackingVolume()->boundarySurfaces())[index]->attachedVolume(*nextPar, dir);
1020 if (!nextVol) {
1021 ATH_MSG_DEBUG(" [+] Detached volume boundary, leaving volume '" << currVol->volumeName() << "'.");
1022 } else {
1023 ATH_MSG_DEBUG(" [+] Detached volume boundary, entering volume '" << nextVol->volumeName() << "'.");
1024 }
1025 currPar = nextPar;
1026 // if ( nextVol || !detachedBoundariesIncluded)
1027 if (nextVol) {
1028 return extrapolateToVolumeWithPathLimit(cache, *currPar, timeLim, dir, particle, nextGeoID, destVol);
1029 }
1030 }
1031 }
1032 iSol++;
1033 }
1034 currPar = nextPar;
1035 }
1036
1037 return returnParameters;
1038}
1039
1040void
1042 const IPropagator &prop,
1043 const TrackParameters &parm,
1044 const TrackParameters &parsOnLayer,
1045 const Layer &lay,
1046 // const TrackingVolume& tvol,
1047 float time,
1048 PropDirection dir,
1049 const BoundaryCheck& bcheck, // bcheck
1050 ParticleHypothesis particle,
1051 bool startingLayer) const {
1052
1053 const EventContext& ctx = Gaudi::Hive::currentContext();
1054 // indicate destination layer
1055 static constexpr bool isDestinationLayer = false;
1056 // start and end surface for on-layer navigation
1057 // -> take the start surface if ther parameter surface is owned by detector element
1058 const Trk::Surface *startSurface = ((parm.associatedSurface()).associatedDetectorElement() && startingLayer) ?
1059 &parm.associatedSurface() : nullptr;
1060 const Trk::Surface * const endSurface = nullptr;
1061 // - the best detSurface to start from is the one associated to the detector element
1062 const Trk::Surface *detSurface = (parsOnLayer.associatedSurface()).associatedDetectorElement() ?
1063 &parsOnLayer.associatedSurface() : nullptr;
1064
1065 ATH_MSG_VERBOSE(" [o] OverlapSearch called " << (startSurface ? "with " : "w/o ") << "start, "
1066 << (endSurface ? "with " : "w/o ") << "end surface.");
1067
1068 if (!detSurface) {
1069 // of parsOnLayer are different from parm, then local position is safe, because the extrapolation
1070 // to the detector surface has been done !
1071 detSurface = isDestinationLayer ? lay.subSurface(parsOnLayer.localPosition()) : lay.subSurface(
1072 parsOnLayer.position());
1073 if (detSurface) {
1074 ATH_MSG_VERBOSE(" [o] Detector surface found through subSurface() call");
1075 } else {
1076 ATH_MSG_VERBOSE(" [o] No Detector surface found on this layer.");
1077 }
1078 } else {
1079 ATH_MSG_VERBOSE(" [o] Detector surface found through parameter on layer association");
1080 }
1081
1082 // indicate the start layer
1083 bool isStartLayer = (detSurface && detSurface == startSurface);
1084
1085 const Trk::TrackParameters *detParameters = nullptr;
1086 // the temporary vector (might have to be ordered)
1087 std::vector<const Trk::TrackParameters*> detParametersOnLayer;
1088 bool reorderDetParametersOnLayer = false;
1089 // the first test for the detector surface to be hit (false test)
1090 // - only do this if the parameters aren't on the surface
1091 // (i.e. search on the start layer or end layer)
1092 if (isDestinationLayer) {
1093 detParameters = (&parsOnLayer);
1094 } else if (isStartLayer) {
1095 detParameters = (&parm);
1096 } else if (detSurface) {
1097 // detParameters = prop.propagate(parm, *detSurface, dir, false, tvol, particle);
1098 detParameters = prop.propagate(ctx,parm, *detSurface, dir, false, m_fieldProperties, particle).release();
1099 }
1100
1101 // set the surface hit to true, it is anyway overruled
1102 bool surfaceHit = true;
1103 if (detParameters &&
1104 !isStartLayer &&
1105 !isDestinationLayer) {
1106 ATH_MSG_VERBOSE(" [o] First intersection with Detector surface: " << *detParameters);
1107 // for the later use in the overlapSearch
1108 //detParameters && detSurface are non-null here
1109 surfaceHit = detSurface->isOnSurface(detParameters->position());
1110
1111 // check also for start/endSurface on this level
1112
1113 surfaceHit = (surfaceHit && startSurface) ?
1114 ((detParameters->position() - parm.position()).dot(dir * parm.momentum().normalized()) >
1115 0) : surfaceHit;
1116 surfaceHit = (surfaceHit && endSurface) ?
1117 ((detParameters->position() - parsOnLayer.position()).dot(dir * parsOnLayer.momentum().normalized()) <
1118 0) : surfaceHit;
1119
1120 // surface is hit within bounds (or at least with given boundary check directive) -> it counts
1121 // surface hit also survived start/endsurface search
1122 //
1123 // Convention for Fatras: always apply the full update on the last parameters
1124 // of the gathered vector (no pre/post schema)
1125 // don't record a hit on the destination surface
1126 if (surfaceHit &&
1127 detSurface != startSurface) {
1128 ATH_MSG_VERBOSE(" [H] Hit with detector surface recorded ! ");
1129 // push into the temporary vector
1130 detParametersOnLayer.push_back(detParameters);
1131 } else if (detParameters) {
1132 // no hit -> fill into the garbage bin
1133 ATH_MSG_VERBOSE(" [-] Detector surface hit cancelled through bounds check or start/end surface check.");
1134 throwIntoGarbageBin(cache,detParameters);
1135 }
1136 }
1137
1138 // search for the overlap ------------------------------------------------------------------------
1139 if (detParameters) {
1140 // retrieve compatible subsurfaces
1141 std::vector<Trk::SurfaceIntersection> cSurfaces;
1142 size_t ncSurfaces = lay.compatibleSurfaces(cSurfaces, *detParameters, Trk::anyDirection, bcheck, false);
1143
1144 // import from StaticEngine.icc
1145 if (ncSurfaces) {
1146 ATH_MSG_VERBOSE("found " << ncSurfaces << " candidate sensitive surfaces to test.");
1147 // now loop over the surfaces:
1148 // the surfaces will be sorted @TODO integrate pathLength propagation into this
1149 for (auto &csf : cSurfaces) {
1150 // propagate to the compatible surface, return types are (pathLimit failure is excluded by Trk::anyDirection for
1151 // the moment):
1152 const Trk::TrackParameters *overlapParameters = prop.propagate(ctx,
1153 parm,
1154 *(csf.object),
1156 true,
1158 particle).release();
1159
1160 if (overlapParameters) {
1161 ATH_MSG_VERBOSE(" [+] Overlap surface was hit, checking start/end surface condition.");
1162 // check on start / end surface for on-layer navigaiton action
1163 surfaceHit = (startSurface) ?
1164 ((overlapParameters->position() - parm.position()).dot(dir * parm.momentum().normalized()) >
1165 0) : true;
1166 surfaceHit = (surfaceHit && endSurface) ?
1167 ((overlapParameters->position() - parsOnLayer.position()).dot(dir *
1168 parsOnLayer.momentum().normalized())
1169 < 0) : surfaceHit;
1170 if (surfaceHit && csf.object!=detSurface) { //skipping the initial surface on which a hit has already been created
1171 ATH_MSG_VERBOSE(" [H] Hit with detector surface recorded !");
1172 // distinguish whether sorting is needed or not
1173 reorderDetParametersOnLayer = true;
1174 // push back into the temporary vector
1175 detParametersOnLayer.push_back(overlapParameters);
1176 } else { // the parameters have been cancelled by start/end surface
1177 // no hit -> fill into the garbage bin
1178 ATH_MSG_VERBOSE(" [-] Detector surface hit cancelled through start/end surface check.");
1179 throwIntoGarbageBin(cache,overlapParameters);
1180 }
1181 }
1182 } // loop over test surfaces done
1183 } // there are compatible surfaces
1184 } // ---------------------------------------------------------------------------------------------
1185
1186 // push them into the parameters vector
1187 std::vector<const Trk::TrackParameters *>::const_iterator parsOnLayerIter = detParametersOnLayer.begin();
1188 std::vector<const Trk::TrackParameters *>::const_iterator parsOnLayerIterEnd = detParametersOnLayer.end();
1189
1190 // reorder the track parameters if neccessary, the overlap descriptor did not provide the ordered surfaces
1191 if (reorderDetParametersOnLayer) {
1192 // sort to reference of incoming parameters
1193 Trk::TrkParametersComparisonFunction parameterSorter(parm.position());
1194 sort(detParametersOnLayer.begin(), detParametersOnLayer.end(), parameterSorter);
1195 }
1196
1197 // after sorting : reset the iterators
1198 parsOnLayerIter = detParametersOnLayer.begin();
1199 parsOnLayerIterEnd = detParametersOnLayer.end();
1200 // now fill them into the parameter vector -------> hit creation done <----------------------
1201 for (; parsOnLayerIter != parsOnLayerIterEnd; ++parsOnLayerIter) {
1202 if (cache.m_hitVector) {
1203 cache.m_hitVector->emplace_back(
1204 std::unique_ptr<const Trk::TrackParameters>(*parsOnLayerIter),
1205 time,
1206 0,
1207 0.);
1208 }
1209 }
1210}
1211
1212std::string
1214 std::stringstream outStream;
1215
1216 if (m_printRzOutput) {
1217 outStream << "[r,phi,z] = [ " << pos.perp() << ", " << pos.phi() << ", " << pos.z() << " ]";
1218 } else {
1219 outStream << "[xyz] = [ " << pos.x() << ", " << pos.y() << ", " << pos.z() << " ]";
1220 }
1221 return outStream.str();
1222}
1223
1224std::string
1226 std::stringstream outStream;
1227
1228 outStream << "[eta,phi] = [ " << mom.eta() << ", " << mom.phi() << " ]";
1229 return outStream.str();
1230}
1231
1232void
1234 const Trk::TrackParameters *trPar) const {
1235 // empty the garbage
1236 std::map<const Trk::TrackParameters *, bool>::iterator garbageIter = cache.m_garbageBin.begin();
1237 std::map<const Trk::TrackParameters *, bool>::iterator garbageEnd = cache.m_garbageBin.end();
1238
1239 bool throwCurrent = false;
1240
1241 for (; garbageIter != garbageEnd; ++garbageIter) {
1242 if (garbageIter->first && garbageIter->first != trPar) {
1243 delete (garbageIter->first);
1244 }
1245 if (garbageIter->first && garbageIter->first == trPar) {
1246 throwCurrent = true;
1247 }
1248 }
1249
1250 cache.m_garbageBin.clear();
1251 if (throwCurrent) {
1253 }
1254}
1255
1256// the validation action -> propagated to the SubTools
1257void
1259 // record the updator validation information
1260 for (const auto *subUpdator : m_subUpdators) {
1261 subUpdator->validationAction();
1262 }
1263 // record the navigator validation information
1264}
1265
1266std::unique_ptr<const Trk::TrackParameters>
1268 Trk::PathLimit &pathLim, Trk::TimeLimit &timeLim,
1270 Trk::ParticleHypothesis particle,
1271 std::vector<Trk::HitInfo> * &hitInfo,
1272 Trk::GeometrySignature &nextGeoID,
1273 const Trk::TrackingVolume *boundaryVol) const {
1275// extrapolation method intended for simulation of particle decay; collects the material up to pre-defined limit and
1276// triggers
1277// material interaction
1278// possible outcomes:1/ returns curvilinear parameters after reaching the maximal path (if to be destroyed)
1279// 2/ returns parameters at destination volume boundary
1280// 3/ returns 0 ( particle stopped ) but keeps material and timing info
1281
1283 "M-[" << ++cache.m_methodSequence << "] transportNeutralsWithPathLimit(...) " << pathLim.x0Max << ", from " <<
1284 parm.position());
1285
1286 // reset the path ( in x0 !!)
1287 cache.m_path = PathLimit(pathLim.x0Max - pathLim.x0Collected, pathLim.process); // collect material locally
1288
1289 // initialize time info
1290 cache.m_time = timeLim.time;
1291
1292 // initialize hit vector
1293 cache.m_hitVector = hitInfo;
1294
1295 cache.m_parametersAtBoundary.resetBoundaryInformation();
1296
1297 // if no input volume, define as highest volume
1298 // const Trk::TrackingVolume* destVolume = boundaryVol ? boundaryVol : m_navigator->highestVolume();
1299 cache.m_currentStatic = nullptr;
1300 if (boundaryVol && !boundaryVol->inside(parm.position(), m_tolerance)) {
1301 return nullptr;
1302 }
1303
1304 cache.m_particleMass = Trk::ParticleMasses::mass[particle];
1305
1306 // extrapolate to destination volume boundary with path limit
1307 std::unique_ptr<const Trk::TrackParameters> returnParms =
1309 cache, parm, timeLim, dir, particle, nextGeoID, boundaryVol);
1310
1311 // save actual path on output
1312 if (cache.m_path.x0Collected > 0.) {
1313 pathLim.updateMat(cache.m_path.x0Collected, cache.m_path.weightedZ / cache.m_path.x0Collected, cache.m_path.l0Collected);
1314 }
1315
1316 // return timing
1317 timeLim.time = cache.m_time;
1318
1319 std::map<const Trk::TrackParameters *, bool>::iterator garbageIter = cache.m_garbageBin.begin();
1320 std::map<const Trk::TrackParameters *, bool>::iterator garbageEnd = cache.m_garbageBin.end();
1321 for (; garbageIter != garbageEnd; ++garbageIter) if (garbageIter->first) {
1322 if(garbageIter->first == returnParms.get()) {
1323 auto ret=returnParms->uniqueClone();
1324 ATH_MSG_DEBUG(" [+] garbage - at "
1325 << positionOutput(garbageIter->first->position())
1326 << " parm=" << garbageIter->first
1327 << " is the return param. Cloning to" << ret.get());
1328 returnParms=std::move(ret);
1329 }
1330 }
1331
1332 return returnParms;
1333}
1334
1335std::unique_ptr<const Trk::TrackParameters>
1338 const Trk::TrackParameters& parm,
1339 Trk::TimeLimit& timeLim,
1341 Trk::ParticleHypothesis particle,
1342 Trk::GeometrySignature& nextGeoID,
1343 const Trk::TrackingVolume* destVol) const
1344{
1345 // returns:
1346 // A) curvilinear track parameters if path or time limit reached
1347 // B) boundary parameters (at destination volume boundary)
1348
1349 // initialize the return parameters vector
1350 std::unique_ptr<const Trk::TrackParameters> returnParameters = nullptr;
1351 const Trk::TrackParameters *currPar = &parm;
1352 const Trk::TrackingVolume *currVol = nullptr;
1353 const Trk::TrackingVolume *nextVol = nullptr;
1354 const Trk::TrackingVolume *assocVol = nullptr;
1355 // int nEntryLays = 0;
1356 unsigned int iDest = 0;
1357
1358 const EventContext& ctx = Gaudi::Hive::currentContext();
1359 // destination volume boundary ?
1360 if (destVol && m_navigator->atVolumeBoundary(currPar, destVol, dir, nextVol, m_tolerance) && nextVol != destVol) {
1361 return parm.uniqueClone();
1362 }
1363
1364 // bool resolveActive = m_resolveActive;
1365 if (!cache.m_highestVolume) {
1366 cache.m_highestVolume = m_navigator->highestVolume(ctx);
1367 }
1368
1369 emptyGarbageBin(cache,&parm);
1370 // transport surfaces: collect only those with valid intersection (easy to calculate for neutrals)
1371 if (cache.m_trSurfs.capacity() > m_maxNavigSurf) {
1372 cache.m_trSurfs.reserve(m_maxNavigSurf);
1373 }
1374 cache.m_trSurfs.clear();
1375
1376 // target volume may not be part of tracking geometry
1377 if (destVol) {
1378 const Trk::TrackingVolume *tgVol = m_navigator->trackingGeometry(ctx)->trackingVolume(destVol->volumeName());
1379 if (!tgVol || tgVol != destVol) {
1380 const auto& bounds = destVol->boundarySurfaces();
1381 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1382 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
1384 dir * currPar->momentum().normalized());
1385 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1386 // boundary check
1387 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1388 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1389 iDest++;
1390 cache.m_trSurfs.emplace_back(&surf, distSol.first());
1391 } // valid intersection
1392 } // along path
1393 if (distSol.numberOfSolutions() > 1 && distSol.second() > 0.) {
1394 // boundary check
1395 Amg::Vector3D gp = currPar->position() + distSol.second() * dir * currPar->momentum().normalized();
1396 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1397 iDest++;
1398 cache.m_trSurfs.emplace_back(&surf, distSol.second());
1399 } // valid intersection
1400 }
1401 } // end loop over boundaries
1402 } // end process external volume
1403 }
1404
1405 // resolve current position
1406 if (cache.m_parametersAtBoundary.nextParameters == currPar) {
1407 cache.m_currentStatic = cache.m_parametersAtBoundary.nextVolume;
1408 } else {
1409 const Amg::Vector3D& gp = parm.position();
1410 if (!cache.m_currentStatic || !cache.m_currentStatic->inside(gp, m_tolerance)) {
1411 cache.m_currentStatic = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(gp);
1412
1413 if (!cache.m_currentStatic ||
1414 !cache.m_currentStatic->inside(currPar->position() + 0.01 * dir * currPar->momentum().normalized(), 0.)) {
1415 cache.m_currentStatic = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(currPar->position()
1416 + 0.01 * dir *
1417 currPar->momentum().normalized());
1418 }
1419 }
1420
1421 if (!cache.m_currentStatic) {
1422 // no next volume found --- end of the world
1423 ATH_MSG_DEBUG(" [+] Word boundary reached - at " << positionOutput(currPar->position()));
1425 return currPar->uniqueClone();
1426 }
1427 }
1428
1429 // current frame volume known-retrieve geoID
1430 if (!cache.m_currentStatic)[[unlikely]] return returnParameters;
1431 //
1432 nextGeoID = cache.m_currentStatic->geometrySignature();
1433
1434 // resolve active Calo volumes if hit info required
1435 if (cache.m_hitVector && nextGeoID == Trk::Calo) {
1436 const Trk::AlignableTrackingVolume *alignTV = dynamic_cast<const Trk::AlignableTrackingVolume *> (cache.m_currentStatic);
1437 if (alignTV) {
1438 const Trk::TrackParameters *aPar = transportInAlignableTV(cache,parm, timeLim, dir, particle, nextGeoID, alignTV).trPar;
1439 if (!aPar) {
1440 return returnParameters;
1441 }
1443 return transportToVolumeWithPathLimit(cache,*aPar, timeLim, dir, particle, nextGeoID, destVol);
1444 }
1445 }
1446
1447 // distance to static volume boundaries recalculated
1448 // retrieve boundaries along path
1449 cache.m_trStaticBounds.clear();
1450 const auto& bounds = cache.m_currentStatic->boundarySurfaces();
1451 for (unsigned int ib = 0; ib < bounds.size(); ++ib) {
1452 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
1454 dir * currPar->momentum().normalized());
1455 if (distSol.numberOfSolutions() > 0 &&
1456 (distSol.currentDistance(false) > m_tolerance || distSol.numberOfSolutions() > 1) &&
1457 distSol.first() > m_tolerance) {
1458 double dist = distSol.first();
1459 // resolve multiple intersection solutions
1460 if (distSol.numberOfSolutions() > 1 && dist < m_tolerance && distSol.second() > dist) {
1461 dist = distSol.second();
1462 }
1463 // boundary check
1464 Amg::Vector3D gp = currPar->position() + dist * dir * currPar->momentum().normalized();
1465 if (surf.isOnSurface(gp, true, m_tolerance, m_tolerance)) {
1466 cache.m_trStaticBounds.insert(cache.m_trStaticBounds.begin(), Trk::DestBound(&surf, dist, ib));
1467 }
1468 } // along path
1469 if (distSol.numberOfSolutions() > 1 && distSol.second() > m_tolerance) {
1470 double dist = distSol.second();
1471 // boundary check
1472 Amg::Vector3D gp = currPar->position() + dist * dir * currPar->momentum().unit();
1473 if (surf.isOnSurface(gp, true, m_tolerance, m_tolerance)) {
1474 if (dist > m_tolerance) { // valid intersection
1475 cache.m_trStaticBounds.insert(cache.m_trStaticBounds.begin(), Trk::DestBound(&surf, dist, ib));
1476 }
1477 }
1478 } // along path
1479 } // end loop over boundaries
1480
1481 if (cache.m_trStaticBounds.empty()) {
1483 " transportToVolumeWithPathLimit() - at " << currPar->position() << ", missing static volume boundary "
1484 << cache.m_currentStatic->volumeName() <<
1485 ": transport interrupted");
1486
1488 "---> particle R,phi,z, momentum:" << currPar->position().perp() << "," << currPar->position().phi() << "," << currPar->position().z() << "," <<
1489 currPar->momentum());
1490 ATH_MSG_DEBUG("---> static volume position:" << cache.m_currentStatic->center());
1491 const Trk::CylinderVolumeBounds *cyl =
1492 dynamic_cast<const Trk::CylinderVolumeBounds *> (&(cache.m_currentStatic->volumeBounds()));
1493 if (cyl) {
1495 "---> cylinder volume dimensions:" << cyl->innerRadius() << "," << cyl->outerRadius() << "," <<
1496 cyl->halflengthZ());
1497 }
1498
1499
1500 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
1501 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
1503 dir * currPar->momentum().unit());
1505 "---> decomposed boundary surface position, normal, estimated distance:" << ib << "," << surf.center() << "," <<
1506 surf.normal());
1508 "---> estimated distance to (first solution):boundary check:" << distSol.numberOfSolutions() << "," << distSol.first() << ":" <<
1509 surf.isOnSurface(currPar->position() + distSol.first() * dir * currPar->momentum().unit(), true,
1511 if (distSol.numberOfSolutions() > 1) {
1512 ATH_MSG_DEBUG("---> estimated distance to (second solution):boundary check:" << distSol.second() << "," <<
1513 surf.isOnSurface(currPar->position() + distSol.second() * dir * currPar->momentum().unit(), true,
1515 }
1516 }
1517
1518 return returnParameters;
1519 } if (cache.m_trStaticBounds[0].distance < m_tolerance) {
1520 // TODO find out why this case (=exit from volume) haven't been handled by Navigator
1521 // ATH_MSG_WARNING( " recovering from glitch at the static volume boundary:"<<cache.m_trStaticBounds[0].distance );
1522
1523 Amg::Vector3D gp = currPar->position() + m_tolerance * dir * currPar->momentum().unit();
1524 cache.m_currentStatic = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(gp);
1525
1526 if (cache.m_currentStatic) {
1527 return transportToVolumeWithPathLimit(cache,parm, timeLim, dir, particle, nextGeoID, destVol);
1528 }
1529 ATH_MSG_DEBUG(" [+] World boundary reached - at " << positionOutput(
1530 currPar->position()) << ", timed at " << cache.m_time);
1532 // if (!destVol) { return currPar;}
1533 return currPar->uniqueClone();
1534
1535 }
1536
1537 cache.m_detachedVols.clear();
1538 cache.m_denseVols.clear();
1539 cache.m_trDenseBounds.clear();
1540 cache.m_trLays.clear();
1541 cache.m_navigLays.clear();
1542
1543 // detached volume boundaries
1544 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const> detVols = cache.m_currentStatic->confinedDetachedVolumes();
1545 if (!detVols.empty()) {
1546 Trk::ArraySpan<const Trk::DetachedTrackingVolume* const>::iterator iTer = detVols.begin();
1547 for (; iTer != detVols.end(); ++iTer) {
1548 // active station ?
1549 const Trk::Layer *layR = (*iTer)->layerRepresentation();
1550 bool active = layR && layR->layerType();
1551
1552 if (active) {
1553 if (!m_resolveMultilayers || (*iTer)->multilayerRepresentation().empty()) {
1554 const Trk::Surface &surf = layR->surfaceRepresentation();
1556 dir * currPar->momentum().normalized());
1557 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1558 // boundary check
1559 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1560 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1561 cache.m_trLays.emplace_back(&surf, distSol.first());
1562 cache.m_navigLays.emplace_back((*iTer)->trackingVolume(), layR);
1563 }
1564 }
1565 } else {
1566 const auto& multi = (*iTer)->multilayerRepresentation();
1567 for (const auto *i : multi) {
1568 const Trk::Surface &surf = i->surfaceRepresentation();
1570 dir * currPar->momentum().normalized());
1571 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1572 // boundary check
1573 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1574 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1575 cache.m_trLays.emplace_back(&surf, distSol.first());
1576 cache.m_navigLays.emplace_back((*iTer)->trackingVolume(), i);
1577 }
1578 }
1579 } // end loop over multilayers
1580 } // end unresolved active
1581 } // active done
1582 else if (cache.m_currentStatic->geometrySignature() != Trk::MS || !m_useMuonMatApprox ||
1583 (*iTer)->name().substr((*iTer)->name().size() - 4, 4) == "PERM") { // retrieve inert detached objects
1584 // only if needed
1585 // dense volume boundaries
1586 if ((*iTer)->trackingVolume()->zOverAtimesRho() != 0. &&
1587 ((*iTer)->trackingVolume()->confinedDenseVolumes().empty())
1588 && ((*iTer)->trackingVolume()->confinedArbitraryLayers().empty())) {
1589 const auto& detBounds = (*iTer)->trackingVolume()->boundarySurfaces();
1590 int newB = 0;
1591 for (unsigned int ibb = 0; ibb < detBounds.size(); ibb++) {
1592 const Trk::Surface &surf = (detBounds[ibb])->surfaceRepresentation();
1594 dir * currPar->momentum().normalized());
1595 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1596 // boundary check
1597 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1598 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1599 cache.m_trDenseBounds.emplace_back(&surf, distSol.first());
1600 newB++;
1601 } // valid intersection
1602 } // along path
1603 } // end loop over boundaries
1604 if (newB > 0) {
1605 cache.m_denseVols.emplace_back((*iTer)->trackingVolume(), newB);
1606 }
1607 }
1608 // subvolumes ?
1609 // if ((*iTer)->trackingVolume()->confinedDenseVolumes() &&
1610 // (*iTer)->trackingVolume()->confinedDenseVolumes()->size())
1611 // ATH_MSG_WARNING( " transportToVolumeWithPathLimit() - at " << currPar->position() <<", unresolved
1612 // subvolumes for "
1613 // << (*iTer)->trackingVolume()->volumeName() );
1614
1615 const auto confinedDense =
1616 (*iTer)->trackingVolume()->confinedDenseVolumes();
1617 if (!confinedDense.empty()) {
1618 auto vIter = confinedDense.begin();
1619 for (; vIter != confinedDense.end(); ++vIter) {
1620 const auto& bounds = (*vIter)->boundarySurfaces();
1621 int newB = 0;
1622 for (unsigned int ibb = 0; ibb < bounds.size(); ibb++) {
1623 const Trk::Surface &surf = (bounds[ibb])->surfaceRepresentation();
1625 dir * currPar->momentum().normalized());
1626 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1627 // boundary check
1628 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1629 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1630 cache.m_trDenseBounds.emplace_back(&surf, distSol.first());
1631 newB++;
1632 } // valid intersection
1633 } // along path
1634 } // end loop over boundaries
1635 if (newB > 0) {
1636 cache.m_denseVols.emplace_back((*vIter), newB);
1637 }
1638 if (!(*vIter)->confinedArbitraryLayers().empty()) {
1640 " transportToVolumeWithPathLimit() - at " << currPar->position() << ", unresolved sublayers/subvolumes for "
1641 << (*vIter)->volumeName());
1642 }
1643 }
1644 }
1645
1646 // confined layers
1647 Trk::ArraySpan<const Trk::Layer* const>confLays = (*iTer)->trackingVolume()->confinedArbitraryLayers();
1648 if (!confLays.empty()) {
1649 for (const Trk::Layer* const lIt: confLays) {
1650 const Trk::Surface &surf = lIt->surfaceRepresentation();
1652 dir * currPar->momentum().normalized());
1653 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1654 // boundary check
1655 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1656 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1657 cache.m_trLays.emplace_back(&surf, distSol.first());
1658 cache.m_navigLays.emplace_back((*iTer)->trackingVolume(), lIt);
1659 } // valid intersection
1660 } // along path
1661 }
1662 } // end confined layers
1663 } // end inert material
1664 }
1665 } // end detached volumes
1666 cache.m_denseResolved = std::pair<unsigned int, unsigned int> (cache.m_denseVols.size(), cache.m_trDenseBounds.size());
1667 cache.m_layerResolved = cache.m_trLays.size();
1668
1669 std::vector< Trk::DestBound >::iterator bIter = cache.m_trStaticBounds.begin();
1670 while (bIter != cache.m_trStaticBounds.end()) {
1671 cache.m_trSurfs.emplace_back((*bIter).surface, (*bIter).distance);
1672 ++bIter;
1673 }
1674
1675 // std::cout <<"navigation in current static:"<< cache.m_trSurfs.size()<<","<<cache.m_trStaticBounds.size()<< std::endl;
1676 // for (unsigned int ib=0; ib<cache.m_trSurfs.size(); ib++) std::cout <<"distance to static:"<<
1677 // ib<<","<<cache.m_trSurfs[ib].second<<std::endl;
1678
1679 // resolve the use of dense volumes
1680 cache.m_dense = (cache.m_currentStatic->geometrySignature() == Trk::MS && m_useMuonMatApprox) ||
1681 (cache.m_currentStatic->geometrySignature() != Trk::MS && m_useDenseVolumeDescription);
1682
1683 // reset remaining counters
1684 cache.m_currentDense = cache.m_dense ? cache.m_currentStatic : cache.m_highestVolume;
1685 cache.m_navigBoundaries.clear();
1686 if (cache.m_denseVols.size() > cache.m_denseResolved.first) {
1687 cache.m_denseVols.resize(cache.m_denseResolved.first);
1688 cache.m_trDenseBounds.resize(cache.m_denseResolved.second);
1689 }
1690 if (cache.m_layers.size() > cache.m_layerResolved) {
1691 cache.m_trLays.resize(cache.m_layerResolved);
1692 cache.m_navigLays.resize(cache.m_layerResolved);
1693 }
1694
1695 // if (cache.m_currentStatic->entryLayerProvider()) nEntryLays = cache.m_currentStatic->entryLayerProvider()->layers().size();
1696
1697 // confined layers
1698 if (cache.m_currentStatic->confinedLayers()) {
1699 std::span <Trk::Layer const * const> cLays = cache.m_currentStatic->confinedLayers()->arrayObjects();
1700 for (const auto *cLay : cLays) {
1701 if (cLay->layerMaterialProperties()) {
1702 const Trk::Surface &surf = cLay->surfaceRepresentation();
1704 dir * currPar->momentum().normalized());
1705 if (distSol.numberOfSolutions() > 0 && distSol.first() > 0.) {
1706 // boundary check
1707 Amg::Vector3D gp = currPar->position() + distSol.first() * dir * currPar->momentum().normalized();
1708 if (surf.isOnSurface(gp, true, 0.001, 0.001)) {
1709 cache.m_trLays.emplace_back(&surf, distSol.first());
1710 cache.m_navigLays.emplace_back(cache.m_currentStatic,
1711 cLay);
1712 } // valid intersection
1713 } // along path
1714 }
1715 }
1716 }
1717
1718 // cache.m_trSurfs contains destination surface (if it exists), static volume boundaries
1719 // complete with TG cache.m_layers/dynamic layers, cache.m_denseBoundaries, cache.m_navigBoundaries, m_detachedBoundaries
1720
1721 if (!cache.m_trLays.empty()) {
1722 cache.m_trSurfs.insert(cache.m_trSurfs.end(), cache.m_trLays.begin(), cache.m_trLays.end());
1723 }
1724 if (!cache.m_trDenseBounds.empty()) {
1725 cache.m_trSurfs.insert(cache.m_trSurfs.end(), cache.m_trDenseBounds.begin(), cache.m_trDenseBounds.end());
1726 }
1727
1728 // current dense
1729 cache.m_currentDense = cache.m_highestVolume;
1730
1731 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
1732 const Trk::TrackingVolume *dVol = cache.m_denseVols[i].first;
1733 if (dVol->inside(currPar->position(), m_tolerance) && dVol->zOverAtimesRho() != 0.) {
1734 if (!m_navigator->atVolumeBoundary(currPar, dVol, dir, nextVol, m_tolerance) ||
1735 dVol->inside(currPar->position() + 2 * m_tolerance * currPar->momentum().unit(), m_tolerance)) {
1736 cache.m_currentDense = dVol;
1737 }
1738 }
1739 }
1740
1741 if (cache.m_dense && cache.m_currentDense == cache.m_highestVolume) {
1742 cache.m_currentDense = cache.m_currentStatic;
1743 }
1744
1745 // ready to process
1746 // 1/ order valid intersections ( already in trSurfs )
1747
1748 std::vector<unsigned int> sols;
1749 sols.reserve(cache.m_trSurfs.size());
1750 for (unsigned int i = 0; i < cache.m_trSurfs.size(); ++i) {
1751 sols.push_back(i);
1752 }
1753
1754 if (sols.size() > 1) {
1755 unsigned int itest = 1;
1756 while (itest < sols.size()) {
1757 if (cache.m_trSurfs[sols[itest]].second < cache.m_trSurfs[sols[itest - 1]].second) {
1758 unsigned int iex = sols[itest - 1];
1759 sols[itest - 1] = sols[itest];
1760 sols[itest] = iex;
1761 itest = 1;
1762 } else {
1763 itest++;
1764 }
1765 }
1766 // check ordering
1767 for (unsigned int is = 1; is < sols.size(); is++) {
1768 if (cache.m_trSurfs[sols[is]].second < cache.m_trSurfs[sols[is - 1]].second) {
1769 std::cout << "wrong intersection ordering" << std::endl;
1770 }
1771 }
1772 }
1773
1774
1775 // 2/ check time/material/boundary limit
1776
1777 // update of cache.m_navigSurfs required if I/ entry into new navig volume, II/ exit from currentActive without overlaps
1778
1779 nextVol = nullptr;
1780 const Trk::TrackParameters *nextPar = nullptr;
1781
1782 double dist = 0.;
1783 double mom = currPar->momentum().mag();
1784 double beta = mom / sqrt(mom * mom + cache.m_particleMass * cache.m_particleMass) * Gaudi::Units::c_light;
1785
1786 ATH_MSG_DEBUG(" [0] starting transport of neutral particle in (dense) volume " << cache.m_currentDense->volumeName());
1787
1788 for (unsigned int sol : sols) {
1789 if (cache.m_trSurfs[sol].second == 0.) {
1790 continue;
1791 }
1792
1793 double step = cache.m_trSurfs[sol].second - dist;
1794
1795 Amg::Vector3D nextPos = currPar->position() + dir * currPar->momentum().normalized() * cache.m_trSurfs[sol].second;
1796 // Amg::Vector3D halfStep = nextPos - 0.5*step*dir*currPar->momentum().normalized();
1797
1798 // check missing volume boundary
1799 if (!(cache.m_currentDense->inside(nextPos, m_tolerance))) {
1800 ATH_MSG_DEBUG(" [!] WARNING: missing volume boundary for volume" << cache.m_currentDense->volumeName());
1801 // new search
1802 cache.m_currentDense = cache.m_highestVolume;
1803 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
1804 const Trk::TrackingVolume *dVol = cache.m_denseVols[i].first;
1805 if (dVol->inside(nextPos, m_tolerance) && dVol->zOverAtimesRho() != 0.) {
1806 cache.m_currentDense = dVol;
1807 }
1808 }
1809 if (cache.m_dense && cache.m_currentDense == cache.m_highestVolume) {
1810 cache.m_currentDense = cache.m_currentStatic;
1811 }
1812
1813 ATH_MSG_DEBUG(" [!] new search for dense volume : " << cache.m_currentDense->volumeName());
1814 }
1815
1816 double tDelta = step / beta;
1817
1818 double mDelta = (cache.m_currentDense->zOverAtimesRho() != 0.) ? step / cache.m_currentDense->x0() : 0.;
1819
1820 // in case of hadronic interaction retrieve nuclear interaction properties, too
1821
1822 double frT = 1.;
1823 if (step > 0 && timeLim.tMax > cache.m_time && cache.m_time + tDelta >= timeLim.tMax) {
1824 frT = (timeLim.tMax - cache.m_time) * beta / step;
1825 }
1826
1827 // TODO : compare x0 or l0 according to the process type
1828 double frM = 1.;
1829 if (mDelta > 0 && cache.m_path.x0Max > 0.) {
1830 if (cache.m_path.process < 100 && cache.m_path.x0Collected + mDelta > cache.m_path.x0Max) {
1831 frM = (cache.m_path.x0Max - cache.m_path.x0Collected) / mDelta;
1832 } else { // waiting for hadronic interaction, retrieve nuclear interaction properties
1833 double mDeltaL = cache.m_currentDense->L0 >
1834 0. ? step / cache.m_currentDense->L0 : mDelta / 0.37 / cache.m_currentDense->averageZ();
1835 if (cache.m_path.l0Collected + mDeltaL > cache.m_path.x0Max) {
1836 frM = (cache.m_path.x0Max - cache.m_path.l0Collected) / mDeltaL;
1837 }
1838 }
1839 }
1840
1841 double fr = fmin(frT, frM);
1842
1843 // std::cout << "looping over intersections:"<<is<<","<< cache.m_trSurfs[sols[is]].second<<","<<step << ","<<
1844 // tDelta<<","<<mDelta << std::endl;
1845
1846 if (fr < 1.) { // decay or material interaction during the step
1847 int process = frT < frM ? timeLim.process : cache.m_path.process;
1848 cache.m_time += fr * step / beta;
1849 if (mDelta > 0 && cache.m_currentDense->averageZ() > 0) {
1850 cache.m_path.updateMat(fr * mDelta, cache.m_currentDense->averageZ(), 0.);
1851 }
1852
1853 nextPos = currPar->position() + dir * currPar->momentum().normalized() * (dist + fr * step);
1854
1855 // process interaction only if creation of secondaries allowed
1856 if (cache.m_currentStatic->geometrySignature() == Trk::ID || m_caloMsSecondary) {
1857 const Trk::TrackParameters* nextPar =
1858 m_updators[0]
1859 ->interact(cache.m_time, nextPos, currPar->momentum(), particle, process, cache.m_currentDense)
1860 .release();
1861
1862 if (nextPar) {
1863 ATH_MSG_DEBUG(" [!] WARNING: particle survives the interaction " << process);
1864 }
1865
1866 if (nextPar && process == 121) {
1867 ATH_MSG_DEBUG(" [!] WARNING: failed hadronic interaction, killing the input particle anyway");
1868 delete nextPar;
1869 return returnParameters;
1870 }
1871
1872 if (!nextPar) {
1873 return returnParameters;
1874 }
1875
1876 throwIntoGarbageBin(cache,nextPar);
1877 // return transportToVolumeWithPathLimit(cache,*nextPar, timeLim, dir, particle, nextGeoID, destVol);
1878 } else { // kill particle without trace
1879 return returnParameters;
1880 }
1881 } // end decay or material interaction durign the step
1882
1883 // update
1884 dist = cache.m_trSurfs[sol].second;
1885 if (mDelta > 0 && cache.m_currentDense->averageZ() > 0) {
1886 cache.m_path.updateMat(mDelta, cache.m_currentDense->averageZ(), 0.);
1887 }
1888 cache.m_time += tDelta;
1889
1890 nextPar = new Trk::CurvilinearParameters(nextPos, currPar->momentum(), 1.); // fake charge
1891 throwIntoGarbageBin(cache,nextPar);
1892
1893 if (sol < iDest) { // destination volume (most often, subdetector boundary)
1894 return nextPar->uniqueClone();
1895 } if (sol < iDest + cache.m_trStaticBounds.size()) { // tracking geometry frame
1896 // material attached ?
1897 const Trk::Layer *mb = cache.m_trStaticBounds[sol - iDest].surface->materialLayer();
1898 if (mb && m_includeMaterialEffects) {
1899 if (mb->layerMaterialProperties() && mb->layerMaterialProperties()->fullMaterial(nextPos)) {
1900 const ITimedMatEffUpdator *currentUpdator = subMaterialEffectsUpdator(*cache.m_currentStatic);
1901 nextPar =
1902 currentUpdator
1903 ? currentUpdator
1904 ->update(
1905 nextPar, *mb, timeLim, cache.m_path, cache.m_currentStatic->geometrySignature(), dir, particle)
1906 .release()
1907 : nextPar;
1908
1909 if (!nextPar) {
1910 ATH_MSG_VERBOSE(" [+] Update may have killed neutral track - return.");
1911 cache.m_parametersAtBoundary.resetBoundaryInformation();
1912 return returnParameters;
1913 }
1914 throwIntoGarbageBin(cache,nextPar);
1915
1916 } else { // material layer without material ?
1917 ATH_MSG_VERBOSE(" boundary layer without material:" << mb->layerIndex());
1918 }
1919 }
1920
1921 // static volume boundary; return to the main loop
1922 unsigned int index = cache.m_trStaticBounds[sol - iDest].bIndex;
1923 // use global coordinates to retrieve attached volume (just for static!)
1924 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
1925 nextPar->position(), nextPar->momentum(), dir);
1926 // double check the next volume
1927 if (nextVol && !(nextVol->inside(nextPar->position() + 0.01 * dir * nextPar->momentum().normalized(), 0.))) {
1929 " [!] WARNING: wrongly assigned static volume ?" << cache.m_currentStatic->volumeName() << "->" <<
1930 nextVol->volumeName());
1931 nextVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(
1932 nextPar->position() + 0.01 * dir * nextPar->momentum().normalized());
1933 if (nextVol) {
1934 ATH_MSG_DEBUG(" new search yields: " << nextVol->volumeName());
1935 }
1936 }
1937 // end double check - to be removed after validation of the geometry gluing
1938 if (nextVol != cache.m_currentStatic) {
1939 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '" << cache.m_currentStatic->volumeName() << "'.");
1940 if (m_navigator->atVolumeBoundary(nextPar, cache.m_currentStatic, dir, assocVol,
1941 m_tolerance) && assocVol != cache.m_currentStatic) {
1942 cache.m_currentDense = cache.m_dense ? nextVol : cache.m_highestVolume;
1943 }
1944 // no next volume found --- end of the world
1945 if (!nextVol) {
1946 ATH_MSG_DEBUG(" [+] World boundary reached - at " << positionOutput(
1947 nextPar->position()) << ", timed at " << cache.m_time);
1949 return nextPar->uniqueClone();
1950 }
1951 // next volume found and parameters are at boundary
1952 if (nextVol /*&& nextPar nextPar is dereferenced anyway*/) {
1953 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
1954 ATH_MSG_DEBUG(" [+] Crossing position is - at " << positionOutput(nextPar->position()));
1955 if (!destVol && cache.m_currentStatic->geometrySignature() != nextVol->geometrySignature()) {
1956 nextGeoID = nextVol->geometrySignature();
1957 return nextPar->uniqueClone();
1958 }
1959 }
1960 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
1961 return transportToVolumeWithPathLimit(cache,*nextPar, timeLim, dir, particle, nextGeoID, destVol);
1962 }
1963 if (dist > 0.) {
1964 return transportToVolumeWithPathLimit(cache,*nextPar, timeLim, dir, particle, nextGeoID, destVol);
1965 }
1966 } else if (sol < iDest + cache.m_trStaticBounds.size() + cache.m_trLays.size()) { // layer
1967 // material thickness - simple approach
1968 unsigned int index = sol - iDest - cache.m_trStaticBounds.size();
1969 const Trk::Layer *nextLayer = cache.m_navigLays[index].second;
1970
1971 bool matUp = nextLayer->layerMaterialProperties()->fullMaterial(nextPos) && m_includeMaterialEffects;
1972
1973 // material update
1974 if (matUp && m_includeMaterialEffects) {
1975 const ITimedMatEffUpdator *currentUpdator = subMaterialEffectsUpdator(*cache.m_currentStatic);
1976
1977 nextPar = currentUpdator ? currentUpdator
1978 ->update(nextPar,
1979 *nextLayer,
1980 timeLim,
1981 cache.m_path,
1982 cache.m_currentStatic->geometrySignature(),
1983 dir,
1984 particle)
1985 .release()
1986 : nextPar;
1987
1988 if (!nextPar) {
1989 ATH_MSG_VERBOSE(" [+] Update may have killed neutral track - return.");
1990 cache.m_parametersAtBoundary.resetBoundaryInformation();
1991 return returnParameters;
1992 }
1993 throwIntoGarbageBin(cache,nextPar);
1994
1995 }
1996 } else if (sol < iDest + cache.m_trStaticBounds.size() + cache.m_trLays.size() + cache.m_trDenseBounds.size()) {
1997 // dense volume boundary : no material update here, navigation only ( set cache.m_currentDense for next step )
1998
1999 unsigned int index = sol - iDest - cache.m_trStaticBounds.size() - cache.m_trLays.size();
2000 std::vector< std::pair<const Trk::TrackingVolume *, unsigned int> >::iterator dIter = cache.m_denseVols.begin();
2001 while (dIter != cache.m_denseVols.end() && index >= (*dIter).second) {
2002 index -= (*dIter).second;
2003 ++dIter;
2004 }
2005 if (dIter != cache.m_denseVols.end()) {
2006 currVol = (*dIter).first;
2007
2008 if (Trk::TrackingGeometry::atVolumeBoundary(nextPos, nextPar->momentum(), currVol, assocVol, dir,
2009 m_tolerance)) {
2010 if (assocVol && assocVol->zOverAtimesRho() != 0.) {
2011 cache.m_currentDense = assocVol;
2012 } else if (currVol->inside(nextPos + 0.002 * dir * nextPar->momentum().normalized())) {
2013 cache.m_currentDense = currVol;
2014 } else {
2015 // new search
2016 cache.m_currentDense = cache.m_highestVolume;
2017 if (m_useMuonMatApprox && cache.m_denseVols.empty()) {
2018 cache.m_currentDense = cache.m_currentStatic;
2019 } else {
2020 for (unsigned int i = 0; i < cache.m_denseVols.size(); i++) {
2021 const Trk::TrackingVolume *dVol = cache.m_denseVols[i].first;
2022 if (dVol->inside(nextPos + 0.002 * dir * nextPar->momentum().normalized(),
2023 m_tolerance) && dVol->zOverAtimesRho() != 0.) {
2024 cache.m_currentDense = dVol;
2025 }
2026 }
2027 }
2028 }
2029 }
2030 }
2031 } else { // detached volume bounds - not relevant ?
2032 }
2033
2034 throwIntoGarbageBin(cache,nextPar);
2035 }
2036
2037
2038
2039 if (nextPar) {
2041 " transportToVolumeWithPathLimit() - return from volume " << cache.m_currentStatic->volumeName() << " at position:" <<
2042 nextPar->position());
2043 return nextPar->uniqueClone();
2044 }
2045 return nullptr;
2046}
2047
2050 const Trk::TrackParameters &parm,
2051 Trk::TimeLimit &timeLim,
2053 Trk::ParticleHypothesis particle,
2054 Trk::GeometrySignature &nextGeoID,
2055 const Trk::AlignableTrackingVolume *aliTV) const {
2056 const std::string m = aliTV ? aliTV->volumeName() : " NULLPTR!";
2057 ATH_MSG_DEBUG(" [0] starting transport of neutral particle in alignable volume " << m);
2058
2059 // material loop in sensitive Calo volumes
2060 // returns: boundary parameters (static volume boundary)
2061 // material collection / intersection with active layers ( binned material used )
2062
2063 // initialize the return parameters vector
2064 const Trk::TrackParameters *currPar = &parm;
2065 const Trk::TrackingVolume *nextVol = nullptr;
2066 std::vector<Trk::IdentifiedIntersection> iis;
2067
2068 emptyGarbageBin(cache,&parm);
2069
2070 const EventContext& ctx = Gaudi::Hive::currentContext();
2071 if (!aliTV) {
2072 return {nullptr, nullptr, nullptr};
2073 }
2074
2075 // TODO if volume entry go to entry of misaligned volume
2076
2077 // save volume entry if collection present
2078
2079 const Trk::BinnedMaterial *binMat = aliTV->binnedMaterial();
2080
2081 const Trk::IdentifiedMaterial *binIDMat = nullptr;
2082
2083 const Trk::Material *currMat = aliTV; // material to be used
2084
2085
2086 // loop through binned material : save identifier, material, distance
2087
2088 // binned material
2089 if (binMat) {
2090 Amg::Vector3D pos = currPar->position();
2091 Amg::Vector3D pot = currPar->position();
2092 Amg::Vector3D umo = currPar->momentum().normalized();
2093
2094 binIDMat = binMat->material(pos);
2095
2096 if (cache.m_hitVector && binIDMat) {
2097 // std::cout <<"id info at the alignable volume entry:"<<binIDMat->second<<std::endl;
2098 if (binIDMat->second > 0) {
2099 cache.m_hitVector->emplace_back(currPar->uniqueClone(), timeLim.time, binIDMat->second, 0.);
2100 }
2101 }
2102
2103 const Trk::BinUtility *lbu = binMat->layerBinUtility(pos);
2104 if (lbu) {
2105 unsigned int cbin = lbu->bin(pos);
2106 // std::cout <<"layerBinUtility retrieved:"<<lbu->bins()<< std::endl;
2107 std::pair<size_t, float> d2n = lbu->distanceToNext(pos, dir * umo);
2108 // std::cout<<"estimated distance to the next bin:"<<d2n.first<<","<<d2n.second<< std::endl;
2109 float dTot = 0.;
2110 float distTot = 0.;
2111 // std::cout <<"input bin:"<<cbin<<", next: "<<d2n.first<<", at distance:"<<d2n.second<< std::endl;
2112 while (true) {
2113 if (d2n.first == cbin) {
2114 break;
2115 }
2116 dTot += d2n.second;
2117 distTot = dTot;
2118 pos = pos + d2n.second * dir * umo;
2119 if (!aliTV->inside(pos)) {
2120 break; // step outside volume
2121 }
2122 cbin = d2n.first;
2123 d2n = lbu->distanceToNext(pos, dir * umo);
2124 if (d2n.first == cbin && fabs(d2n.second) < 0.002) { // move ahead
2125 pos = pos + 0.002 * dir * umo;
2126 dTot += 0.002;
2127 d2n = lbu->distanceToNext(pos, dir * umo);
2128 }
2129 // std::cout <<"finding next bin?:"<<d2n.first<<","<<dTot<<"+"<<d2n.second<< std::endl;
2130 if (d2n.second > 0.001) { // retrieve material and save bin entry
2131 pot = pos + 0.5 * d2n.second * dir * umo;
2132 binIDMat = binMat->material(pot);
2133 iis.emplace_back(distTot, binIDMat->second, binIDMat->first.get());
2134 // std::cout <<"saving next bin entry:"<< distTot<<","<<binIDMat->second<<std::endl;
2135 }
2136 }
2137 }
2138 }
2139
2140 // resolve exit from the volume
2141
2142 cache.m_trStaticBounds.clear();
2143 const auto &bounds = aliTV->boundarySurfaces();
2144 for (unsigned int ib = 0; ib < bounds.size(); ib++) {
2145 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
2147 dir * currPar->momentum().normalized());
2148 double dist = distSol.first();
2149 // resolve multiple intersection solutions
2150 if (distSol.numberOfSolutions() > 1 && dist < m_tolerance && distSol.second() > dist) {
2151 dist = distSol.second();
2152 }
2153 // boundary check
2154 Amg::Vector3D gp = currPar->position() + dist * dir * currPar->momentum().normalized();
2155 // std::cout<<"alignable volume boundary:"<< ib<<","<<dist<<","<<
2156 // surf.isOnSurface(gp,true,m_tolerance,m_tolerance)<<std::endl;
2157 if (dist > m_tolerance && surf.isOnSurface(gp, true, m_tolerance, m_tolerance)) {
2158 const Trk::TrackingVolume *attachedVol = (bounds[ib])->attachedVolume(gp, currPar->momentum(), dir);
2159
2160 if (attachedVol && !(attachedVol->inside(gp + 0.01 * dir * currPar->momentum().normalized(), m_tolerance))) {
2162 " [!] WARNING: wrongly assigned exit volume ?" << cache.m_currentStatic->volumeName() << "->" <<
2163 attachedVol->volumeName());
2164 attachedVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(
2165 gp + 0.01 * dir * currPar->momentum().normalized());
2166 if (attachedVol) {
2167 ATH_MSG_DEBUG(" new search yields: " << attachedVol->volumeName());
2168 }
2169 }
2170
2171 if (attachedVol != cache.m_currentStatic) { // exit
2172 nextVol = attachedVol;
2173 cache.m_trStaticBounds.insert(cache.m_trStaticBounds.begin(), Trk::DestBound(&surf, dist, ib));
2174 } else if (dist > 0.001) {
2175 const Trk::TrackingVolume *testVol = (bounds[ib])->attachedVolume(gp,
2176 currPar->momentum(),
2179 "gluing problem at the exit from alignable volume: " << gp.perp() << "," << gp.z() << ":" <<
2180 cache.m_currentStatic->volumeName());
2181 if (testVol) {
2182 ATH_MSG_DEBUG("inverted direction:" << testVol->volumeName());
2183 }
2184 if (testVol &&
2185 testVol->inside(gp + 0.01 * dir * currPar->momentum().normalized(),
2186 m_tolerance) && testVol != cache.m_currentStatic) {
2188 "next volume resolved to:" << testVol->volumeName() << " at the position(R,Z):" << gp.perp() << "," <<
2189 gp.z());
2190 nextVol = testVol;
2191 cache.m_trStaticBounds.insert(cache.m_trStaticBounds.begin(), Trk::DestBound(&surf, dist, ib));
2192 }
2193 }
2194 }
2195 } // end loop over boundaries
2196
2197 // if (nextVol) std::cout <<"nextVol, number of exit solutions:"<<
2198 // nextVol->volumeName()<<","<<cache.m_trStaticBounds.size()<< std::endl;
2199
2200 if (cache.m_trStaticBounds.empty()) {
2201 ATH_MSG_WARNING("exit from alignable volume " << aliTV->volumeName() << " not resolved, aborting");
2202 return {nullptr, nullptr, nullptr};
2203 } if (cache.m_trStaticBounds.size() > 1) { // hit edge ?
2204 Amg::Vector3D gp = currPar->position() + (cache.m_trStaticBounds[0].distance + 1.) * dir *
2205 currPar->momentum().normalized();
2206 nextVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(gp);
2207 ATH_MSG_DEBUG("exit volume reassigned:" << nextVol->volumeName());
2208 }
2209
2210 // exit from the volume may coincide with the last bin boundary - leave 10 microns marge
2211 if (!iis.empty() && cache.m_trStaticBounds[0].distance - iis.back().distance < 0.01) {
2212 iis.pop_back();
2213 }
2214
2215 // add volume exit
2216 iis.emplace_back(cache.m_trStaticBounds[0].distance, 0, nullptr);
2217
2218 // loop over intersection taking into account the material effects
2219
2220 double dist = 0.;
2221 double mom = currPar->momentum().mag();
2222 double beta = mom / sqrt(mom * mom + cache.m_particleMass * cache.m_particleMass) * Gaudi::Units::c_light;
2223 Amg::Vector3D nextPos = currPar->position();
2224
2225 int currLay = 0;
2226
2227 for (unsigned int is = 0; is < iis.size(); is++) {
2228 if (iis[is].distance == 0.) {
2229 continue;
2230 }
2231
2232 double step = iis[is].distance - dist;
2233
2234 nextPos = currPar->position() + dir * currPar->momentum().normalized() * iis[is].distance;
2235
2236 double tDelta = step / beta;
2237
2238 double mDelta = (currMat->zOverAtimesRho() != 0.) ? step / currMat->x0() : 0.;
2239
2240 // in case of hadronic interaction retrieve nuclear interaction properties, too
2241
2242 double frT = 1.;
2243 if (step > 0 && timeLim.tMax > cache.m_time && cache.m_time + tDelta >= timeLim.tMax) {
2244 frT = (timeLim.tMax - cache.m_time) * beta / step;
2245 }
2246
2247 // TODO : compare x0 or l0 according to the process type
2248 double frM = 1.;
2249 if (mDelta > 0 && cache.m_path.x0Max > 0.) {
2250 if (cache.m_path.process < 100 && cache.m_path.x0Collected + mDelta > cache.m_path.x0Max) {
2251 frM = (cache.m_path.x0Max - cache.m_path.x0Collected) / mDelta;
2252 } else { // waiting for hadronic interaction, retrieve nuclear interaction properties
2253 double mDeltaL = currMat->L0 > 0. ? step / currMat->L0 : mDelta / 0.37 / currMat->averageZ();
2254 if (cache.m_path.l0Collected + mDeltaL > cache.m_path.x0Max) {
2255 frM = (cache.m_path.x0Max - cache.m_path.l0Collected) / mDeltaL;
2256 }
2257 }
2258 }
2259
2260 double fr = fmin(frT, frM);
2261
2262 // std::cout << "looping over intersections:"<<is<<","<< cache.m_trSurfs[sols[is]].second<<","<<step << ","<<
2263 // tDelta<<","<<mDelta << std::endl;
2264
2265 if (fr < 1.) { // decay or material interaction during the step
2266 int process = frT < frM ? timeLim.process : cache.m_path.process;
2267 cache.m_time += fr * step / beta;
2268 if (mDelta > 0 && currMat->averageZ() > 0) {
2269 cache.m_path.updateMat(fr * mDelta, currMat->averageZ(), 0.);
2270 }
2271
2272 nextPos = currPar->position() + dir * currPar->momentum().normalized() * (dist + fr * step);
2273
2274 // process interaction only if creation of secondaries allowed
2275 if (m_caloMsSecondary) {
2276 const Trk::TrackParameters* nextPar =
2277 m_updators[0]
2278 ->interact(cache.m_time, nextPos, currPar->momentum(), particle, process, currMat)
2279 .release();
2280 throwIntoGarbageBin(cache, nextPar);
2281
2282 if (nextPar) {
2283 ATH_MSG_DEBUG(" [!] WARNING: particle survives the interaction " << process);
2284 }
2285
2286 if (nextPar && process == 121) {
2287 ATH_MSG_DEBUG(" [!] WARNING: failed hadronic interaction, killing the input particle anyway");
2288 return {nullptr, nullptr, nullptr};
2289 }
2290
2291 if (!nextPar) {
2292 return {nullptr, nullptr, nullptr};
2293 }
2294
2295 // return transportToVolumeWithPathLimit(*nextPar, timeLim, dir, particle, nextGeoID, destVol);
2296 } else { // kill particle without trace ?
2297 return {nullptr, nullptr, nullptr};
2298 }
2299 } // end decay or material interaction during the step
2300
2301 // update
2302 dist = iis[is].distance;
2303 if (mDelta > 0 && currMat->averageZ() > 0) {
2304 cache.m_path.updateMat(mDelta, currMat->averageZ(), 0.);
2305 }
2306 cache.m_time += tDelta;
2307
2308 if (is < iis.size() - 1) { // update bin material info
2309 // binIDMat = binMat->material(nextPos);
2310 // currMat = binIDMat->first;
2311 currMat = iis[is].material;
2312 currLay = iis[is].identifier;
2313
2314 if (cache.m_hitVector && iis[is].identifier > 0) { // save entry to the next layer
2315 ATH_MSG_VERBOSE("active layer entry:" << currLay << " at R,z:" << nextPos.perp() << "," << nextPos.z());
2316 auto nextPar = std::make_unique<Trk::CurvilinearParameters>(nextPos, currPar->momentum(), 0.);
2317 cache.m_hitVector->emplace_back(std::move(nextPar), timeLim.time, iis[is].identifier, 0.);
2318 }
2319 }
2320 } // end loop over intersections
2321
2322 Trk::CurvilinearParameters *nextPar = new Trk::CurvilinearParameters(nextPos, currPar->momentum(), 0.);
2323
2324 if (cache.m_hitVector) { // save volume exit /active layer only ?
2325 ATH_MSG_VERBOSE("active layer/volume exit:" << currLay << " at R,z:" << nextPos.perp() << "," << nextPos.z());
2326 if (binIDMat and(binIDMat->second > 0)) {
2327 cache.m_hitVector->emplace_back(nextPar->uniqueClone(), timeLim.time, currLay, 0.);
2328 }
2329 }
2330
2331 throwIntoGarbageBin(cache,nextPar);
2332
2333
2334
2335 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '" << cache.m_currentStatic->volumeName() << "'.");
2336
2337 // no next volume found --- end of the world
2338 if (!nextVol) {
2339 ATH_MSG_DEBUG(" [+] World boundary reached - at " << positionOutput(
2340 nextPar->position()) << ", timed at " << cache.m_time);
2342 } else {
2343 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
2344 ATH_MSG_DEBUG(" [+] Crossing position is - at " << positionOutput(nextPar->position()));
2345 }
2346
2347 cache.m_parametersAtBoundary.boundaryInformation(nextVol, nextPar, nextPar);
2348
2349 return {nextPar, nextVol, cache.m_currentStatic};
2350}
2351
2354 const Trk::TrackParameters &parm,
2355 Trk::TimeLimit &timeLim,
2357 Trk::ParticleHypothesis particle,
2358 Trk::GeometrySignature &nextGeoID,
2359 const Trk::AlignableTrackingVolume *vol) const {
2360 const std::string m = vol ? vol->volumeName():"NULLPTR";
2361 ATH_MSG_DEBUG("M-[" << ++cache.m_methodSequence << "] extrapolateInAlignableTV(...) " << m);
2362
2363 // material loop in sensitive Calo volumes
2364 // extrapolation without target surface returns:
2365 // A) boundary parameters (static volume boundary)
2366 // if target surface:
2367 // B) trPar at target surface
2368 // material collection done by the propagator ( binned material used )
2369
2370 // initialize the return parameters vector
2371 const Trk::TrackParameters *currPar = &parm;
2372 const Trk::AlignableTrackingVolume *staticVol = nullptr;
2373 const Trk::TrackingVolume *currVol = nullptr;
2374 const Trk::TrackingVolume *nextVol = nullptr;
2375 std::vector<unsigned int> solutions;
2376 // double tol = 0.001;
2377 // double path = 0.;
2378 const EventContext& ctx = Gaudi::Hive::currentContext();
2379 if (!cache.m_highestVolume) {
2380 cache.m_highestVolume = m_navigator->highestVolume(ctx);
2381 }
2382
2383 emptyGarbageBin(cache,&parm);
2384
2385 // verify current position
2386 const Amg::Vector3D& gp = parm.position();
2387 if (vol && vol->inside(gp, m_tolerance)) {
2388 staticVol = vol;
2389 } else {
2390 currVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(gp);
2391 const Trk::TrackingVolume *nextStatVol = nullptr;
2392 if (m_navigator->atVolumeBoundary(currPar, currVol, dir, nextStatVol, m_tolerance) && nextStatVol != currVol) {
2393 currVol = nextStatVol;
2394 }
2395 if (currVol && currVol != vol) {
2396 const Trk::AlignableTrackingVolume *aliTG = dynamic_cast<const Trk::AlignableTrackingVolume *> (currVol);
2397 if (aliTG) {
2398 staticVol = aliTG;
2399 }
2400 }
2401 }
2402
2403 if (!staticVol) {
2404 ATH_MSG_DEBUG(" [!] failing in retrieval of AlignableTV, return 0");
2405 return {nullptr, nullptr, nullptr};
2406 }
2407
2408 // TODO if volume entry go to entry of misaligned volume
2409
2410 // save volume entry if collection present
2411
2412 if (cache.m_hitVector) {
2413 const Trk::BinnedMaterial *binMat = staticVol->binnedMaterial();
2414 if (binMat) {
2415 const Trk::IdentifiedMaterial *binIDMat = binMat->material(currPar->position());
2416 if (binIDMat->second > 0) {
2417 cache.m_hitVector->emplace_back(currPar->uniqueClone(), timeLim.time, binIDMat->second, 0.);
2418 }
2419 }
2420 }
2421
2422 // navigation surfaces
2423 if (cache.m_navigSurfs.capacity() > m_maxNavigSurf) {
2424 cache.m_navigSurfs.reserve(m_maxNavigSurf);
2425 }
2426 cache.m_navigSurfs.clear();
2427
2428 // assume new static volume, retrieve boundaries
2429 cache.m_currentStatic = staticVol;
2430 cache.m_staticBoundaries.clear();
2431 const auto &bounds = staticVol->boundarySurfaces();
2432 for (unsigned int ib = 0; ib < bounds.size(); ++ib) {
2433 const Trk::Surface &surf = (bounds[ib])->surfaceRepresentation();
2434 cache.m_staticBoundaries.emplace_back(&surf, true);
2435 }
2436
2437 cache.m_navigSurfs.insert(cache.m_navigSurfs.end(), cache.m_staticBoundaries.begin(), cache.m_staticBoundaries.end());
2438
2439 // current dense
2440 cache.m_currentDense = staticVol;
2441
2442 // ready to propagate
2443 // till: A/ static volume boundary(bcheck=true) , B/ destination surface(bcheck=false)
2444
2445 nextVol = nullptr;
2446 while (currPar) {
2447 std::vector<unsigned int> solutions;
2448 // propagate now
2449 ATH_MSG_DEBUG(" [+] Starting propagation at position " << positionOutput(currPar->position())
2450 << " (current momentum: " << currPar->momentum().mag() <<
2451 ")");
2452 ATH_MSG_DEBUG(" [+] " << cache.m_navigSurfs.size() << " target surfaces in '" << cache.m_currentDense->volumeName() << "'.");
2453 // arguments : inputParameters, vector of navigation surfaces, propagation direction, b field service, particle
2454 // type, result,
2455 // material collection, intersection collection, path limit, switch for use of path limit, switch for
2456 // curvilinear on return, current TG volume
2457 const Trk::TrackParameters* nextPar = m_stepPropagator
2458 ->propagateT(ctx,
2459 *currPar,
2460 cache.m_navigSurfs,
2461 dir,
2463 particle,
2464 solutions,
2465 cache.m_path,
2466 timeLim,
2467 true,
2468 cache.m_currentDense,
2469 cache.m_hitVector)
2470 .release();
2471 ATH_MSG_VERBOSE(" [+] Propagation done. ");
2472 if (nextPar) {
2473 ATH_MSG_DEBUG(" [+] Position after propagation - at " << positionOutput(nextPar->position()));
2474 }
2475
2476 if (nextPar) {
2477 ATH_MSG_DEBUG(" [+] Number of intersection solutions: " << solutions.size());
2478 }
2479 if (nextPar) {
2480 throwIntoGarbageBin(cache,nextPar);
2481 }
2482
2483 // material update has been done already by the propagator
2484 if (cache.m_path.x0Max > 0. &&
2485 ((cache.m_path.process < 100 && cache.m_path.x0Collected >= cache.m_path.x0Max) ||
2486 (cache.m_path.process > 100 && cache.m_path.l0Collected >= cache.m_path.x0Max))) {
2487 // trigger presampled interaction, provide material properties if needed
2488 // process interaction only if creation of secondaries allowed
2489 if (cache.m_currentStatic->geometrySignature() == Trk::ID || m_caloMsSecondary) {
2490 const Trk::Material *extMprop = cache.m_path.process > 100 ? cache.m_currentDense : nullptr;
2491
2492 const Trk::TrackParameters *iPar = nullptr;
2493 if (nextPar) {
2494 iPar =
2495 m_updators[0]
2496 ->interact(
2497 timeLim.time, nextPar->position(), nextPar->momentum(), particle, cache.m_path.process, extMprop)
2498 .release();
2499 }
2500
2501 if (!iPar) {
2502 return {nullptr, nullptr, nullptr};
2503 }
2504
2506
2507 if (iPar && cache.m_path.process == 121) {
2508 ATH_MSG_DEBUG(" [!] WARNING: failed hadronic interaction, killing the input particle anyway");
2509 return {nullptr, nullptr, nullptr};
2510 }
2511
2512 // return transportToVolumeWithPathLimit(*nextPar, timeLim, dir, particle, nextGeoID, destVol);
2513 } else { // kill particle without trace ?
2514 return {nullptr, nullptr, nullptr};
2515 }
2516 }
2517
2518 // decay ?
2519 if (timeLim.tMax > 0. && timeLim.time >= timeLim.tMax) {
2520 // process interaction only if creation of secondaries allowed
2521 if (cache.m_currentStatic->geometrySignature() == Trk::ID || m_caloMsSecondary) {
2522 // trigger presampled interaction
2523 const Trk::TrackParameters* iPar = m_updators[0]->interact(
2524 timeLim.time, nextPar->position(), nextPar->momentum(), particle, timeLim.process).release();
2525 if (!iPar) {
2526 return {nullptr, nullptr, nullptr};
2527 }
2528
2530 ATH_MSG_WARNING("particle decay survival?" << particle << "," << timeLim.process);
2531 return {nullptr, nullptr, nullptr};
2532 } // kill the particle without trace ( some validation info can be included here eventually )
2533 return {nullptr, nullptr, nullptr};
2534
2535 }
2536
2537 if (nextPar) {
2538 unsigned int iSol = 0;
2539 while (iSol < solutions.size()) {
2540 if (solutions[iSol] < cache.m_staticBoundaries.size()) {
2541 // TODO if massive boundary coded, add the material effects here
2542 // static volume boundary; return to the main loop : TODO move from misaligned to static
2543 unsigned int index = solutions[iSol];
2544 // use global coordinates to retrieve attached volume (just for static!)
2545 nextVol = (cache.m_currentStatic->boundarySurfaces())[index]->attachedVolume(
2546 nextPar->position(), nextPar->momentum(), dir);
2547 // double check the next volume
2548 if (nextVol && !(nextVol->inside(nextPar->position() + 0.01 * dir * nextPar->momentum().normalized(), 0.))) {
2550 " [!] WARNING: wrongly assigned static volume ?" << cache.m_currentStatic->volumeName() << "->" <<
2551 nextVol->volumeName());
2552 nextVol = m_navigator->trackingGeometry(ctx)->lowestStaticTrackingVolume(
2553 nextPar->position() + 0.01 * dir * nextPar->momentum().normalized());
2554 if (nextVol) {
2555 ATH_MSG_DEBUG(" new search yields: " << nextVol->volumeName());
2556 }
2557 }
2558 // end double check - to be removed after validation of the geometry gluing
2559 // lateral exit from calo sample can be handled here
2560 if (cache.m_hitVector) {
2561 const Trk::BinnedMaterial *binMat = staticVol->binnedMaterial();
2562 if (binMat) {
2563 const Trk::IdentifiedMaterial *binIDMat = binMat->material(nextPar->position());
2564 // save only if entry to the sample present, the exit missing and non-zero step in the sample
2565 if (binIDMat && binIDMat->second > 0 && !cache.m_hitVector->empty() &&
2566 cache.m_hitVector->back().detID == binIDMat->second) {
2567 // double s = (nextPar->position()-m_identifiedParameters->back().first->position()).mag();
2568 // if (s>0.001) m_identifiedParameters->push_back(std::pair<const Trk::TrackParameters*,int>
2569 // (nextPar->clone(), -binIDMat->second));
2570 cache.m_hitVector->emplace_back(nextPar->uniqueClone(), timeLim.time, -binIDMat->second, 0.);
2571 }
2572 }
2573 }
2574 // end lateral exit handling
2575
2576 ATH_MSG_DEBUG(" [+] StaticVol boundary reached of '" << cache.m_currentStatic->volumeName() << "'.");
2577 // no next volume found --- end of the world
2578 if (!nextVol) {
2579 ATH_MSG_DEBUG(" [+] World boundary reached - at " << positionOutput(
2580 nextPar->position()) << ", timed at " << cache.m_time);
2582 } else {
2583 ATH_MSG_DEBUG(" [+] Crossing to next volume '" << nextVol->volumeName() << "'");
2584 ATH_MSG_DEBUG(" [+] Crossing position is - at " << positionOutput(nextPar->position()));
2585 }
2586
2587 return {nextPar, nextVol, cache.m_currentStatic};
2588 }
2589 }
2590 }
2591
2592 currPar = nextPar;
2593 }
2594
2595 return {nullptr, nullptr, nullptr};
2596}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
size_t size() const
Number of registered mappings.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Base Class for a navigation object (active) in the Calo realm.
const BinnedMaterial * binnedMaterial() const
access to binned material
A generic symmetric BinUtility, for fully symmetric binning in terms of binning grid and binning type...
Definition BinUtility.h:39
std::pair< size_t, float > distanceToNext(const Amg::Vector3D &position, const Amg::Vector3D &direction, size_t ba=0) const
Distance estimate to next bin.
Definition BinUtility.h:158
size_t bin(const Amg::Vector3D &position, size_t ba=0) const
Bin from a 3D vector (already in binning frame).
Definition BinUtility.h:126
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
for description of non-homogenous dense volumes
const IdentifiedMaterial * material(const Amg::Vector3D &position) const
access to material/id per bin
const Trk::BinUtility * layerBinUtility(const Amg::Vector3D &position) const
access to layer bin utility
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
Bounds for a cylindrical Volume, the decomposeToSurfaces method creates a vector of up to 6 surfaces:
double innerRadius() const
This method returns the inner radius.
double halflengthZ() const
This method returns the halflengthZ.
double outerRadius() const
This method returns the outer radius.
Base Class for a navigation object (active/passive) in the Tracking realm.
Access to distance solutions.
double second() const
Distance to second intersection solution along direction (for a cylinder surface).
double currentDistance(bool signedDist=false) const
Current distance to surface (spatial), signed (along/opposite to surface normal) if input argument tr...
int numberOfSolutions() const
Number of intersection solutions.
double first() const
Distance to first intersection solution along direction.
Interface class IPropagators It inherits from IAlgTool.
Definition IPropagator.h:54
Interface class for the updater AlgTool, it inherits from IAlgTool Detailed information about private...
virtual std::unique_ptr< TrackParameters > update(const TrackParameters *parm, const Layer &sf, TimeLimit &time, PathLimit &path, Trk::GeometrySignature geoID, PropDirection dir=alongMomentum, ParticleHypothesis particle=pion) const =0
Updator interface (full update for a layer): The parmeters are given as a const pointer.
virtual const MaterialProperties * fullMaterial(const Amg::Vector3D &gp) const =0
Return method for full material description of the Layer.
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
size_t compatibleSurfaces(std::vector< SurfaceIntersection > &cSurfaces, const TrackParameters &pars, PropDirection pdir, const BoundaryCheck &bcheck, bool materialSurfacesOnly=true, const Surface *startSurface=nullptr, const Surface *endSurface=nullptr, const ICompatibilityEstimator *ice=nullptr) const
get compatible surfaces starting from charged parameters
int layerType() const
get the Layer coding
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
const MaterialProperties * fullUpdateMaterialProperties(const TrackParameters &par) const
getting the MaterialProperties back - for full update
Definition Layer.cxx:169
virtual bool isOnLayer(const Amg::Vector3D &gp, const BoundaryCheck &bcheck=BoundaryCheck(true)) const
isOnLayer() method, using isOnSurface() with Layer specific tolerance
Definition Layer.cxx:135
const Layer * nextLayer(const Amg::Vector3D &gp, const Amg::Vector3D &udir) const
getting the next/previous Layer if registered - unit for direction vector required
Definition Layer.cxx:161
const SurfaceArray * surfaceArray() const
Return the entire SurfaceArray, returns nullptr if no SurfaceArray.
const LayerMaterialProperties * layerMaterialProperties() const
getting the LayerMaterialProperties including full/pre/post update
const Surface * subSurface(const Amg::Vector3D &gp) const
If no subSurface array is defined or no subSurface can be found to the given Amg::Vector3D,...
Definition Layer.cxx:107
magnetic field properties to steer the behavior of the extrapolation
A common object to be contained by.
Definition Material.h:117
float x0() const
Definition Material.h:227
float averageZ() const
Definition Material.h:228
float zOverAtimesRho() const
access to members
Definition Material.h:226
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
std::unique_ptr< ParametersBase< DIM, T > > uniqueClone() const
clone method for polymorphic deep copy returning unique_ptr; it is not overriden, but uses the existi...
Amg::Vector2D localPosition() const
Access method for the local coordinates, local parameter definitions differ for each surface type.
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
const TrkDetElementBase * associatedDetectorElement() const
return associated Detector Element
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const =0
fast straight line distance evaluation to Surface
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
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
const Amg::Vector3D & center() const
Returns the center position of the Surface.
BoundaryTrackParameters transportInAlignableTV(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters &parm, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, Trk::GeometrySignature &nextGeoId, const Trk::AlignableTrackingVolume *aliTV) const
ToolHandleArray< IPropagator > m_propagators
TimedExtrapolator(const std::string &, const std::string &, const IInterface *)
Constructor.
BooleanProperty m_resolveActive
BooleanProperty m_printRzOutput
BooleanProperty m_useDenseVolumeDescription
virtual StatusCode finalize() override
AlgTool finalize method.
virtual std::unique_ptr< const Trk::TrackParameters > transportNeutralsWithPathLimit(const Trk::TrackParameters &parm, Trk::PathLimit &pathLim, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, std::vector< Trk::HitInfo > *&hitVector, Trk::GeometrySignature &nextGeoId, const Trk::TrackingVolume *boundaryVol=nullptr) const override
Transport method for neutral, possibly unstable particles.
BooleanProperty m_resolveMultilayers
std::unique_ptr< const Trk::TrackParameters > extrapolateToVolumeWithPathLimit(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters &parm, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, Trk::GeometrySignature &nextGeoID, const Trk::TrackingVolume *destVol) const
ToolHandle< INavigator > m_navigator
ToolHandleArray< ITimedMatEffUpdator > m_updators
StringArrayProperty m_propNames
ToolHandleArray< IMultipleScatteringUpdator > m_msupdators
Trk::MagneticFieldProperties m_fieldProperties
ToolHandle< IPropagator > m_stepPropagator
BooleanProperty m_useMuonMatApprox
BooleanProperty m_includeMaterialEffects
BoundaryTrackParameters extrapolateInAlignableTV(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters &parm, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, Trk::GeometrySignature &nextGeoId, const Trk::AlignableTrackingVolume *aliTV) const
virtual void validationAction() const override
Validation Action: Can be implemented optionally, outside access to internal validation steps.
static std::string momentumOutput(const Amg::Vector3D &mom)
For the output - global momentum.
virtual ~TimedExtrapolator()
Destructor.
std::string positionOutput(const Amg::Vector3D &pos) const
Private method for conversion of the synchronized geometry signature to the natural subdetector order...
virtual std::unique_ptr< const Trk::TrackParameters > extrapolateWithPathLimit(const Trk::TrackParameters &parm, Trk::PathLimit &pathLim, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, std::vector< Trk::HitInfo > *&hitVector, Trk::GeometrySignature &nextGeoID, const Trk::TrackingVolume *boundaryVol=nullptr) const override
Extrapolation method for charged, possibly unstable particles.
std::vector< const IPropagator * > m_subPropagators
Propagators to chose from (steered by signature).
unsigned int m_configurationLevel
see the supported levels of configuration above
std::vector< const ITimedMatEffUpdator * > m_subUpdators
Updators to chose from (steered by signature).
void emptyGarbageBin(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters *) const
Private method for emptying the GarbageBin.
StringArrayProperty m_updatNames
std::unique_ptr< const Trk::TrackParameters > transportToVolumeWithPathLimit(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters &parm, Trk::TimeLimit &time, Trk::PropDirection dir, Trk::ParticleHypothesis particle, Trk::GeometrySignature &nextGeoId, const Trk::TrackingVolume *boundaryVol) const
BooleanProperty m_caloMsSecondary
const ITimedMatEffUpdator * subMaterialEffectsUpdator(const TrackingVolume &tvol) const
Access the subPropagator to the given volume.
virtual StatusCode initialize() override
AlgTool initailize method.
void throwIntoGarbageBin(Trk::TimedExtrapolator::Cache &cache, const Trk::TrackParameters *garbage) const
Private method for throwing into the GarbageBin.
BooleanProperty m_robustSampling
void overlapSearch(Trk::TimedExtrapolator::Cache &cache, const IPropagator &prop, const TrackParameters &parm, const TrackParameters &parsOnLayer, const Layer &lay, float time, PropDirection dir=anyDirection, const BoundaryCheck &bcheck=true, ParticleHypothesis particle=pion, bool startingLayer=false) const
Private to search for overlap surfaces.
static bool atVolumeBoundary(const Amg::Vector3D &gp, const TrackingVolume *vol, double tol)
check position at volume boundary
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
const LayerArray * confinedLayers() const
Return the subLayer array.
GeometrySignature geometrySignature() const
return the Signature
const Layer * associatedLayer(const Amg::Vector3D &gp) const
Return the associated Layer.
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
const TrackingVolume * associatedSubVolume(const Amg::Vector3D &gp) const
Return the associated sub Volume, returns THIS if no subVolume exists.
std::vector< std::shared_ptr< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
const std::string & volumeName() const
Returns the VolumeName - for debug reason, might be depreciated later.
const Layer * nextLayer(const Amg::Vector3D &gp, const Amg::Vector3D &mom, bool asres=true, bool skipNavLayer=false) const
Return the next Layer if existing, NULL if no next layer corresponds.
ArraySpan< Layer const *const > confinedArbitraryLayers() const
Return the confined subLayer array.
ArraySpan< TrackingVolume const *const > confinedDenseVolumes() const
Return unordered subVolumes - not the ownership.
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition Volume.cxx:72
const std::string process
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312
Eigen::Matrix< double, 3, 1 > Vector3D
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
Ensure that the ATLAS eigen extensions are properly loaded.
PropDirection
PropDirection, enum for direction of the propagation.
@ oppositeMomentum
@ anyDirection
std::span< T > ArraySpan
CurvilinearParametersT< TrackParametersDim, Charged, PlaneSurface > CurvilinearParameters
ComparisonFunction< TrackParameters > TrkParametersComparisonFunction
@ FastField
call the fast field access method of the FieldSvc
@ FullField
Field is set to be realistic, but within a given Volume.
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
std::pair< std::shared_ptr< Material >, int > IdentifiedMaterial
@ NumberOfSignatures
ParametersBase< TrackParametersDim, Charged > TrackParameters
const IIntersectionCache * cache() const
Retrieve the associated cache block, if it exists.
@ active
Definition Layer.h:47
Definition index.py:1
#define unlikely(x)
const TrackParameters * trPar
void updateMat(float dX0, float Z, float dL0)
collected material update