ATLAS Offline Software
Loading...
Searching...
No Matches
RungeKuttaIntersector.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6// Runge-Kutta method for tracking a particle through a magnetic field
7// (c) ATLAS Detector software
9
10#include <cmath>
11#include <iomanip>
20#include "TrkSurfaces/Surface.h"
21
22namespace{
23
24bool
25isTrapped(const double distance,
26 double& previousDistance,
27 unsigned long long& stepsUntilTrapped)
28{
29 // catch loopers
30 if (distance > previousDistance) {
31 return true;
32 }
33
34 if (stepsUntilTrapped <= 0) {
35 return true;
36 }
37
38 --stepsUntilTrapped;
39
40 // store previous value to check steps are converging (with 10% safety factor)
41 previousDistance = 1.1 * distance;
42
43 return false;
44}
45
46}//end anonymous namespace
47namespace Trk
48{
49
51 const std::string& name,
52 const IInterface* parent)
53 : base_class (type, name, parent) {}
54
55StatusCode
57 // print name and package version
58 ATH_MSG_DEBUG( "RungeKuttaIntersector::initialize()" );
59
60 // retrieve MagneticFieldTool and StraightLineIntersector
62
63 // productionMode gives steplengths tuned for use in production (adequate precision),
64 // otherwise take very small steps for maximum precision but with a heavy execution penalty
65 if (! m_productionMode){
66 m_shortStepMax = 500.*Gaudi::Units::nanometer;
67 m_stepMax0 = 1.8*Gaudi::Units::mm;
68 m_stepMax1 = 1.8*Gaudi::Units::mm;
69 m_stepMax2 = 1.8*Gaudi::Units::mm;
70 m_stepMax3 = 1.8*Gaudi::Units::mm;
71 m_stepMax4 = 1.8*Gaudi::Units::mm;
72 m_stepsUntilTrapped = 20000;
73 }
74
75 return StatusCode::SUCCESS;
76}
77
78StatusCode
80{
82 {
83 msg(MSG::INFO) << "finalized after " << m_countExtrapolations << " extrapolations,";
84 double norm = 1./static_cast<double>(m_countExtrapolations);
85 msg(MSG::INFO) << std::setiosflags(std::ios::fixed)
86 << " taking an average" << std::setw(7) << std::setprecision(1)
87 << norm*static_cast<double>(m_countStep)
88 << " full steps," << std::setw(5) << std::setprecision(2)
89 << norm*static_cast<double>(m_countStepReduction)
90 << " step reductions and" << std::setw(5) << std::setprecision(2)
91 << norm*static_cast<double>(m_countShortStep)
92 << " short final steps";
93 msg(MSG::INFO) << endmsg;
94 }
95
96 return StatusCode::SUCCESS;
97}
98
100std::optional<Trk::TrackSurfaceIntersection>
102 const TrackSurfaceIntersection& trackIntersection,
103 const double qOverP) const
104{
105 // trap low momentum
106 if (std::abs(qOverP) > m_momentumThreshold)
107 {
108 ATH_MSG_DEBUG(" trapped as below momentum threshold" );
109 return std::nullopt;
110 }
111
112 const auto surfaceType = surface.type();
113 if (surfaceType == Trk::SurfaceType::Plane) {
114 return intersectPlaneSurface(static_cast<const PlaneSurface&>(surface),
115 trackIntersection, qOverP);
116 }
117 if (surfaceType == Trk::SurfaceType::Line) {
119 static_cast<const StraightLineSurface&>(surface), trackIntersection,
120 qOverP);
121 }
122 if (surfaceType == Trk::SurfaceType::Cylinder) {
124 static_cast<const CylinderSurface&>(surface), trackIntersection,
125 qOverP);
126 }
127 if (surfaceType == Trk::SurfaceType::Disc) {
128 return intersectDiscSurface(static_cast<const DiscSurface&>(surface),
129 trackIntersection, qOverP);
130 }
131 if (surfaceType == Trk::SurfaceType::Perigee) {
132 return approachPerigeeSurface(static_cast<const PerigeeSurface&>(surface),
133 trackIntersection, qOverP);
134 }
135
136 ATH_MSG_WARNING( " unrecognized Surface" );
137 return std::nullopt;
138}
139
141std::optional<Trk::TrackSurfaceIntersection>
143 const TrackSurfaceIntersection& trackIntersection,
144 const double qOverP) const
145{
147 TrackSurfaceIntersection isect = trackIntersection;
148 const Amg::Vector3D& pos = isect.position();
149 const double rStart = pos.perp();
150 const double zStart = pos.z();
151 MagField::AtlasFieldCache fieldCache;
152 initializeFieldCache(fieldCache);
153 Amg::Vector3D fieldValue = field(pos, fieldCache);
154
155 // straight line distance along track to closest approach to line
156 const Amg::Vector3D& lineDirection = (surface.transform().rotation()).col(2);
157 double stepLength = 0;
158 double distance = distanceToLine (isect, surface.center(),lineDirection, stepLength);
159 unsigned long long stepsUntilTrapped = m_stepsUntilTrapped;
160 double previousDistance = 1.1*distance;
161
162 // integration loop (step)
163 while (distance > m_shortStepMax)
164 {
165 if (isTrapped(distance, previousDistance, stepsUntilTrapped)) {
166 // trapped
167 if (msgLvl(MSG::DEBUG)) debugFailure (std::move(isect), surface, qOverP,
168 rStart, zStart, true);
169 return std::nullopt;
170 }
171 assignStepLength(isect, stepLength);
172 step(isect, fieldValue, stepLength, qOverP, fieldCache);
173 distance = distanceToLine (isect, surface.center(),lineDirection, stepLength);
174 }
175
176 // if intersection OK: make short final step to surface - assuming constant field
177 if (distance > m_shortStepMin) shortStep(isect, fieldValue, stepLength, qOverP);
178 return newIntersection(std::move(isect), surface, qOverP,
179 rStart, zStart);
180}
181
183std::optional<Trk::TrackSurfaceIntersection>
185 const TrackSurfaceIntersection& trackIntersection,
186 const double qOverP) const
187{
189 TrackSurfaceIntersection isect = trackIntersection;
190 const Amg::Vector3D& pos = isect.position();
191 const double rStart = pos.perp();
192 const double zStart = pos.z();
193 MagField::AtlasFieldCache fieldCache;
194 initializeFieldCache(fieldCache);
195 Amg::Vector3D fieldValue = field(pos, fieldCache);
196
197 // straight line distance along track to closest approach to line
198 const Amg::Vector3D& lineDirection = (surface.transform().rotation()).col(2);
199 double stepLength = 0;
200 double distance = distanceToLine (isect, surface.center(),lineDirection, stepLength);
201 unsigned long long stepsUntilTrapped = m_stepsUntilTrapped;
202 double previousDistance = 1.1*distance;
203
204 // integration loop (step)
205 while (distance > m_shortStepMax)
206 {
207 if (isTrapped(distance, previousDistance, stepsUntilTrapped)) {
208 // trapped
209 if (msgLvl(MSG::DEBUG)) debugFailure (std::move(isect), surface, qOverP,
210 rStart, zStart, true);
211 return std::nullopt;
212 }
213 assignStepLength(isect, stepLength);
214 step(isect, fieldValue, stepLength, qOverP,fieldCache);
215 distance = distanceToLine (isect, surface.center(),lineDirection, stepLength);
216 }
217
218 // if intersection OK: make short final step assuming constant field
219 if (distance > m_shortStepMin) shortStep(isect, fieldValue, stepLength, qOverP);
220 return newIntersection(std::move(isect), surface, qOverP,
221 rStart, zStart);
222}
223
225std::optional<Trk::TrackSurfaceIntersection>
227 const TrackSurfaceIntersection& trackIntersection,
228 const double qOverP) const
229{
231 TrackSurfaceIntersection isect = trackIntersection;
232 const Amg::Vector3D& pos = isect.position();
233 const double rStart = pos.perp();
234 const double zStart = pos.z();
235 MagField::AtlasFieldCache fieldCache;
236 initializeFieldCache(fieldCache);
237 Amg::Vector3D fieldValue = field(pos, fieldCache);
238
239 // calculate straight line distance along track to intersect with cylinder radius
240 double cylinderRadius = (surface.globalReferencePoint() - surface.center()).perp();
241 Amg::Vector3D offset = surface.center() - isect.position();
242 double rCurrent = offset.perp();
243 double stepLength = 0;
244 double distance = distanceToCylinder (isect, cylinderRadius,rCurrent,offset, stepLength);
245 unsigned long long stepsUntilTrapped = m_stepsUntilTrapped;
246 double previousDistance = 1.1*distance;
247 bool trapped = false;
248
249 // integration loop (step)
250 while (distance > m_shortStepMax)
251 {
252 if (isTrapped(distance, previousDistance, stepsUntilTrapped)) {
253 trapped = true;
254 break;
255 }
256 assignStepLength(isect, stepLength);
257 double rPrevious= rCurrent;
258 step(isect, fieldValue, stepLength, qOverP,fieldCache);
259 offset = surface.center() - isect.position();
260 rCurrent = offset.perp();
261 double deltaR1 = rCurrent - rPrevious;
262 double deltaR2 = cylinderRadius - rCurrent;
263 double scale = 1.;
264 if (deltaR1 != 0.) scale = deltaR2 / deltaR1;
265 if (scale < 1.)
266 {
267 stepLength *= scale;
268 if (scale < -1.) {
269 trapped = true;
270 break;
271 }
272 }
273 distance = std::abs(stepLength);
274 }
275
276 // if intersection OK: make short final step assuming constant field
277 if (! trapped
278 && std::abs(cylinderRadius - rCurrent) < m_shortStepMax)
279 {
280 distance = distanceToCylinder (isect, cylinderRadius,rCurrent,offset, stepLength);
281 // protect against divergence (looping)
282 if (distance < m_shortStepMax)
283 {
284 if (distance > m_shortStepMin) shortStep(isect, fieldValue, stepLength, qOverP);
285 return newIntersection(std::move(isect), surface, qOverP,
286 rStart, zStart);
287 }
288 }
289
290 // trapped
291 if (msgLvl(MSG::DEBUG)) debugFailure (std::move(isect), surface, qOverP,
292 rStart, zStart, true);
293 return std::nullopt;
294}
295
297std::optional<Trk::TrackSurfaceIntersection>
299 const TrackSurfaceIntersection& trackIntersection,
300 const double qOverP) const
301{
303 TrackSurfaceIntersection isect = trackIntersection;
304 const Amg::Vector3D& pos = isect.position();
305 const double rStart = pos.perp();
306 const double zStart = pos.z();
307 MagField::AtlasFieldCache fieldCache;
308 initializeFieldCache(fieldCache);
309 Amg::Vector3D fieldValue = field(pos, fieldCache);
310
311 // straight line distance along track to intersect with disc
312 double stepLength = 0;
313 double distance = distanceToDisc (isect, surface.center().z(), stepLength);
314 unsigned long long stepsUntilTrapped = m_stepsUntilTrapped;
315 double previousDistance = 1.1*distance;
316
317 // integration loop
318 while (std::abs(stepLength) > m_shortStepMax)
319 {
320 if (isTrapped(distance, previousDistance, stepsUntilTrapped)) {
321 // trapped
322 if (msgLvl(MSG::DEBUG)) debugFailure (std::move(isect), surface, qOverP,
323 rStart, zStart, true);
324 return std::nullopt;
325 }
326 assignStepLength(isect, stepLength);
327 step(isect, fieldValue, stepLength, qOverP,fieldCache);
328 distance = distanceToDisc (isect, surface.center().z(), stepLength);
329 }
330
331 // if intersection OK: make short final step assuming constant field
332 if (std::abs(stepLength) > m_shortStepMin) shortStep(isect, fieldValue, stepLength, qOverP);
333 return newIntersection(std::move(isect), surface, qOverP,
334 rStart, zStart);
335}
336
338std::optional<Trk::TrackSurfaceIntersection>
340 const TrackSurfaceIntersection& trackIntersection,
341 const double qOverP) const
342{
344 TrackSurfaceIntersection isect = trackIntersection;
345 const Amg::Vector3D& pos = isect.position();
346 const double rStart = pos.perp();
347 const double zStart = pos.z();
348 MagField::AtlasFieldCache fieldCache;
349 initializeFieldCache(fieldCache);
350 Amg::Vector3D fieldValue = field(pos, fieldCache);
351
352 // straight line distance along track to intersect with plane
353 double stepLength = 0;
354 double distance = distanceToPlane (isect, surface.center(),surface.normal(), stepLength);
355 unsigned long long stepsUntilTrapped = m_stepsUntilTrapped;
356 double previousDistance = 1.1*distance;
357
358 // integration loop (step)
359 while (distance > m_shortStepMax)
360 {
361 if (isTrapped(distance, previousDistance, stepsUntilTrapped)) {
362 // trapped
363 if (msgLvl(MSG::DEBUG)) debugFailure (std::move(isect), surface, qOverP,
364 rStart, zStart, true);
365 return std::nullopt;
366 }
367 assignStepLength(isect, stepLength);
368 step(isect, fieldValue, stepLength, qOverP, fieldCache);
369 distance = distanceToPlane (isect, surface.center(),surface.normal(), stepLength);
370 }
371
372 // if intersection OK: make short final step assuming constant field
373 if (distance > m_shortStepMin) shortStep(isect, fieldValue, stepLength, qOverP);
374 return newIntersection(std::move(isect), surface, qOverP,
375 rStart, zStart);
376}
377
378
379//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>>
380
381void
383 double& stepLength) const
384{
385 const Amg::Vector3D& pos = isect.position();
386 const double sinTheta = isect.direction().perp();
387
388 // step length assigned according to abs value of current rz position
389 // use default (large) value for most regions of InDet and Calo
390 // TODO: consider bounded steps acc region => solves in/outwards problem
391 const double zCurrent = std::abs(pos.z());
392 const double rCurrent = pos.perp();
393 double stepMax = m_stepMax3;
394 // m_stepFlag = 0;
395
396 // first treat InDet and Solenoid regions
397 // TODO: so far validated out to R = 1.0m
398 if (rCurrent < m_solenoidR && zCurrent < m_solenoidZ) {
399 if (rCurrent < m_inDetR2) {
400 // inner barrel, forward tracks and endcap regions generally happy
401 // with long steps double number of steps for middle barrel and much
402 // of the transition region
403 if (zCurrent < m_inDetZ0 && rCurrent < m_inDetR0) {
404 // inner barrel
405 // stepMax = m_stepMax3;
406 } else if (zCurrent > m_inDetZ2 || sinTheta < 0.35) {
407 // endcap and far forward
408 // stepMax = m_stepMax3;
409 }
410
411 // double number of steps for most of the remainder
412 else if (zCurrent > m_inDetZ1 && sinTheta < 0.60) {
413 // barrel:endcap transition
414 stepMax = m_stepMax2;
415 } else if (rCurrent > m_inDetR0) {
416 // middle barrel
417 stepMax = m_stepMax2;
418 }
419
420 // the remaining transition region requires much shorter steps
421 else {
422 if (rCurrent > m_inDetR1) {
423 // middle/outer transition region
424 stepMax = m_stepMax1;
425 } else {
426 // inner transition (anomalous behaviour causing low pt track
427 // rotation)
428 stepMax = m_stepMax0;
429 }
430 }
431 }
432 // take care when moving to region with shorter steps
433
434 // field less uniform (approaching coil structure)
435 else if (rCurrent < 1000.) // 1000
436 {
437 if (zCurrent > 700.) {
438 // stepMax = m_stepMax3;
439 // exception at higher radii (influence of coil structure)
440 if (rCurrent > 850.)
441 stepMax = m_stepMax2;
442 }
443 // // double number of steps for most of the remainder
444 else if (zCurrent > 420. && sinTheta < 0.60) {
445 // barrel:endcap transition
446 stepMax = m_stepMax2;
447 } else {
448 // decrease step length with increasing radius
449 if (rCurrent > 900.) {
450 // coil structure
451 stepMax = m_stepMax0;
452 } else {
453 // middle
454 stepMax = m_stepMax1;
455 }
456 }
457 } else {
458 // field less uniform in vicinity of solenoid coils
459 stepMax = m_stepMax1;
460 if (zCurrent < 3000.)
461 stepMax = m_stepMax0;
462 }
463 }
464
465 // secondly treat MuonSpectrometer regions
466 // start with central barrel
467 else if (rCurrent > m_muonR0 && zCurrent < m_toroidZ4) // Z3
468 {
469 // ++m_count0;
470 // optimize - only refresh phi occasionally
471 double period = M_PI / 4.;
472 double phi = pos.phi() + 0.5 * period;
473 if (phi < 0.)
474 phi += 2. * M_PI;
475 int n = static_cast<int>(phi / period);
476 phi -= static_cast<double>(n) * period;
477 if (phi > 0.5 * period)
478 phi = period - phi;
479
480 // sol 1: 12.1 full steps, 0.34 reduc, 0 short
481 // sol 2: 12.0 full steps, 0.34 reduc, 0 short
482 // sol 3: 11.9 full steps, 0.34 reduc, 0 short (tidy-up)
483 double radius = rCurrent;
484 if (stepLength < 0.)
485 radius -= m_stepMax2;
486 if (zCurrent > m_toroidZ3 && phi < 0.04) {
487 // fringe and coil regions
488 stepMax = m_stepMax1;
489 // m_stepFlag = 22;
490 // ++m_count5;
491 } else if (radius < 5300.) {
492 // fringe and coil regions
493 stepMax = m_stepMax1;
494 // m_stepFlag = 21;
495 // ++m_count1;
496 }
497 // note: long sector (phi>0.175) has max 1/3 outer steps as finishes at
498 // lower r try: phi-extended long sector with stepMax3 for all r > 5500
499 else if (phi > 0.04 ||
500 (radius > 5500. &&
501 (radius < 9000. ||
502 (phi > 0.028 && radius < 9350.)))) // (extended) long sector
503 {
504 // central 'aircore' between coils
505 stepMax = m_stepMax3;
506 // m_stepFlag = 27;
507 // ++m_count2;
508 } else if (radius > 5500. && radius < 9350.) {
509 // outer coil fringe region
510 stepMax = m_stepMax2;
511 // m_stepFlag = 28;
512 // ++m_count3;
513 } else {
514 // outer coil region
515 stepMax = m_stepMax1;
516 // m_stepFlag = 29;
517 // ++m_count4;
518 }
519 } else if (rCurrent > m_muonR0 || zCurrent > m_muonZ0) {
520 if (zCurrent > m_toroidZ4) {
521 if (zCurrent > m_toroidZ8) {
522 // essentially out of any toroid fields
523 stepMax = m_stepMax4;
524 } else if (zCurrent > m_toroidZ7) {
525 // toroid exit fringe fields
526 stepMax = m_stepMax3;
527 } else if (rCurrent > m_toroidR0 && rCurrent < m_toroidR1 &&
528 zCurrent > m_toroidZ5 && zCurrent < m_toroidZ6) {
529 // endcap toroid central field
530 stepMax = m_stepMax3;
531 } else {
532 // endcap toroid high field gradient and barrel coil regions
533 stepMax = m_stepMax1;
534 }
535 } else if (rCurrent > m_toroidR3) {
536 // main region of barrel toroid :
537 // generally take long steps but with care near coil end loop
538 if (zCurrent < m_toroidZ2) {
539 stepMax = m_stepMax4;
540 // if (rCurrent > 9000.) stepMax = m_stepMax3;
541 // if (rCurrent > 9400.) stepMax = m_stepMax2;
542 } else if (zCurrent < m_toroidZ3) {
543 stepMax = m_stepMax3;
544 } else {
545 stepMax = m_stepMax1;
546 }
547 } else if (rCurrent > m_toroidR2) {
548 // toroid field after inner barrel or outer endcap coil
549 stepMax = m_stepMax3;
550 } else if (zCurrent < m_toroidZ0 || zCurrent > m_toroidZ1 ||
551 rCurrent > m_muonR0) {
552 // small steps in toroid high field regions and near iron structures
553 stepMax = m_stepMax1;
554 } else {
555 // endcap toroid entrance fringe fields
556 stepMax = m_stepMax3;
557 }
558 }
559
560 // finally assign Calo regions
561 else {
562 if ((rCurrent < m_solenoidR) ||
563 (rCurrent > m_caloR0 && rCurrent < m_caloR1) ||
564 rCurrent > m_caloR3 ||
565 (zCurrent > m_caloZ1 && zCurrent < m_caloZ2) ||
566 zCurrent > m_caloZ3) {
567 stepMax = m_stepMax1;
568 } else if ((rCurrent > m_caloR2 && rCurrent < m_caloR4) ||
569 zCurrent > m_caloZ0) {
570 stepMax = m_stepMax2;
571 }
572 }
573
574 // finally reset stepLength as necessary
575 if (std::abs(stepLength) < stepMax)
576 return;
577 if (stepLength > 0.) {
578 stepLength = stepMax;
579 } else {
580 stepLength = -stepMax;
581 }
582}
583
584void
586 const Surface& surface,
587 const double qOverP,
588 const double rStart,
589 const double zStart,
590 const bool trapped) const
591{
592 // forget low momentum (prone to looping...)
593 if (std::abs(qOverP) > m_momentumWarnThreshold) return;
594
595 double pt = 1.E+8;
596 const double sinTheta = isect.direction().perp();
597 if (qOverP != 0.) pt = sinTheta/(qOverP*Gaudi::Units::GeV);
598
599 const double rCurrent = isect.position().perp();
600
601 MsgStream log(msgSvc(), name());
602 if (rCurrent > rStart)
603 {
604 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right)
605 << " fail to intersect surface when extrapolating outwards from R,Z"
606 << std::setw(8) << std::setprecision(1) << rStart << ","
607 << std::setw(7) << std::setprecision(0) << zStart << " mm, with pt"
608 << std::setw(7) << std::setprecision(2) << pt << " GeV, direction eta"
609 << std::setw(5) << std::setprecision(2) << isect.direction().eta();
610 }
611 else
612 {
613 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right)
614 << " fail to intersect surface when extrapolating inwards from R,Z"
615 << std::setw(8) << std::setprecision(1) << rStart << ","
616 << std::setw(7) << std::setprecision(0) << zStart << " mm, with pt"
617 << std::setw(7) << std::setprecision(2) << pt << " GeV, direction eta"
618 << std::setw(5) << std::setprecision(2) << isect.direction().eta();
619 }
620 // if (trapped) log << MSG::DEBUG << " looping in mag field ";
621 log << MSG::DEBUG << endmsg;
622
623 if (dynamic_cast<const PlaneSurface*>(&surface))
624 {
625 double stepLength = 0;
626 (void)distanceToPlane (isect, surface.center(),surface.normal(), stepLength);
627 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right) << " PlaneSurface"
628 << " at R,Z" << std::setw(8) << std::setprecision(1) << surface.center().perp() << ","
629 << std::setw(7) << std::setprecision(0) << surface.center().z()
630 << " at line distance " << std::setw(9) << std::setprecision(1) << stepLength;
631 // if (trapped) log << MSG::DEBUG << " looping in mag field ";
632 log << MSG::DEBUG << endmsg;
633 }
634 else if (dynamic_cast<const CylinderSurface*>(&surface))
635 {
636 double cylinderRadius = (surface.globalReferencePoint() - surface.center()).perp();
637 Amg::Vector3D offset = surface.center() - isect.position();
638 double rCurrent = offset.perp();
639 double stepLength = 0;
640 double distance = distanceToCylinder (isect, cylinderRadius,rCurrent,offset, stepLength);
641 if (distance < m_shortStepMin)
642 {
643 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right)
644 << " closest approach to CylinderSurface at radius "
645 << std::setw(9) << std::setprecision(4) << rCurrent
646 << " mm. Cylinder radius " << std::setw(9) << std::setprecision(4) << cylinderRadius << " mm"
647 << endmsg;
648 }
649 else
650 {
651 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right) << " CylinderSurface"
652 << " radius " << std::setw(6) << std::setprecision(1) << cylinderRadius
653 << " rCurrent " << std::setw(6) << std::setprecision(1) << rCurrent
654 << " distance " << std::setw(6) << std::setprecision(1) << stepLength;
655 if (trapped) log << MSG::DEBUG << " looping in mag field ";
656 log << MSG::DEBUG << endmsg;
657 }
658 }
659 else if (dynamic_cast<const DiscSurface*>(&surface))
660 {
661 double stepLength = 0;
662 (void)distanceToDisc (isect, surface.center().z(), stepLength);
663 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right) << " DiscSurface"
664 << " at R,Z" << std::setw(8) << std::setprecision(1) << surface.center().perp() << ","
665 << std::setw(7) << std::setprecision(0) << surface.center().z()
666 << " at line distance " << std::setw(9) << std::setprecision(1) << stepLength;
667 if (trapped) log << MSG::DEBUG << " looping in mag field ";
668 log << MSG::DEBUG << endmsg;
669 }
670 else if (dynamic_cast<const PerigeeSurface*>(&surface))
671 {
672 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right) << " PerigeeSurface "
673 << endmsg;
674 }
675 else if (dynamic_cast<const StraightLineSurface*>(&surface))
676 {
677 log << MSG::DEBUG << std::setiosflags(std::ios::fixed|std::ios::right) << " StraightLineSurface "
678 << endmsg;
679 }
680 log << MSG::DEBUG << endmsg;
681}
682
683void
685 const Amg::Vector3D& fieldValue,
686 const double stepLength,
687 const double qOverP) const
688{
689 Amg::Vector3D& pos = isect.position();
690 Amg::Vector3D& dir = isect.direction();
691 const double cOverP = Gaudi::Units::c_light*qOverP;
692
693 // as step except for const field assumption
694 double stepOverP = 0.5*stepLength*cOverP;
695 Amg::Vector3D product0 = stepOverP*dir.cross(fieldValue);
696 // intermediate point (half way through step)
697 Amg::Vector3D direction1 = dir + product0;
698 Amg::Vector3D product1 = stepOverP*direction1.cross(fieldValue);
699 Amg::Vector3D direction2 = dir + product1;
700 Amg::Vector3D product2 = stepOverP*direction2.cross(fieldValue);
701 // step end point
702 pos += stepLength*(dir + m_third*(product0+product1+product2));
703 Amg::Vector3D direction3 = dir + 2.*product2;
704 Amg::Vector3D product3 = stepOverP*direction3.cross(fieldValue);
705 dir += m_third*(product0+product3 + 2.*(product1+product2));
706 isect.pathlength() += stepLength;
708}
709
710void
712 Amg::Vector3D& fieldValue,
713 double& stepLength,
714 const double qOverP,
715 MagField::AtlasFieldCache &fieldCache) const
716{
717 Amg::Vector3D& pos = isect.position();
718 Amg::Vector3D& dir = isect.direction();
719 const double cOverP = Gaudi::Units::c_light*qOverP;
720
721 double stepOverP = 0.5*stepLength*cOverP;
722 Amg::Vector3D product0 = stepOverP*dir.cross(fieldValue);
723
724 // intermediate field look-up point (half way through step)
725 Amg::Vector3D position1 = pos + 0.5*stepLength*(dir + 0.5*product0);
726 Amg::Vector3D fieldValue1 = field(position1, fieldCache);
727 Amg::Vector3D direction1 = dir + product0;
728 Amg::Vector3D product1 = stepOverP*direction1.cross(fieldValue1);
729 Amg::Vector3D direction2 = dir + product1;
730 Amg::Vector3D product2 = stepOverP*direction2.cross(fieldValue1);
731
732 // field look-up at step end point
733 Amg::Vector3D offsetAtEnd = stepLength*(dir + m_third*(product0+product1+product2));
734 Amg::Vector3D fieldAtEnd = field(pos+offsetAtEnd, fieldCache);
735
736 // redo with reduced stepLength if non-uniform field derivative detected
737 if ((fieldValue1 - 0.5 * (fieldValue + fieldAtEnd)).mag() > 0.00001 &&
738 std::abs(stepLength) > m_stepMax0) {
739 if (stepLength > 0.) {
740 stepLength = m_stepMax0;
741 } else {
742 stepLength = -m_stepMax0;
743 }
745 stepOverP = 0.5 * stepLength * cOverP;
746 product0 = stepOverP * dir.cross(fieldValue);
747 // intermediate point (half way through step)
748 Amg::Vector3D position1p =
749 pos + 0.5 * stepLength * (dir + 0.5 * product0);
750 Amg::Vector3D fieldValue1p = field(position1p, fieldCache);
751 Amg::Vector3D direction1p = dir + product0;
752 product1 = stepOverP * direction1p.cross(fieldValue1p);
753 Amg::Vector3D direction2p = dir + product1;
754 product2 = stepOverP * direction2p.cross(fieldValue1p);
755 // step end point
756 offsetAtEnd =
757 stepLength * (dir + m_third * (product0 + product1 + product2));
758 fieldAtEnd = field(pos + offsetAtEnd, fieldCache);
759 }
760
761 Amg::Vector3D direction3 = dir + 2. * product2;
762 Amg::Vector3D product3 = stepOverP * direction3.cross(fieldAtEnd);
763 dir += m_third * (product0 + product3 + 2. * (product1 + product2));
764 fieldValue = fieldAtEnd;
765 pos += offsetAtEnd;
766 isect.pathlength() += stepLength;
767 ++m_countStep;
768}
769
770} // end of namespace
#define M_PI
Scalar mag() const
mag method
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Class for a CylinderSurface in the ATLAS detector.
virtual const Amg::Vector3D & globalReferencePoint() const override final
Returns a global reference point: For the Cylinder this is Where denotes the averagePhi() of the cy...
Class for a DiscSurface in the ATLAS detector.
Definition DiscSurface.h:54
Class describing the Line to which the Perigee refers to.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
virtual std::optional< TrackSurfaceIntersection > intersectDiscSurface(const DiscSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : DiscSurface.
virtual StatusCode initialize() override
std::optional< TrackSurfaceIntersection > newIntersection(TrackSurfaceIntersection &&isect, const Surface &surface, const double qOverP, const double rStart, const double zStart) const
virtual std::optional< TrackSurfaceIntersection > approachPerigeeSurface(const PerigeeSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PerigeeSurface.
void debugFailure(TrackSurfaceIntersection &&isect, const Surface &surface, const double qOverP, const double rStart, const double zStart, const bool trapped) const
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
void step(TrackSurfaceIntersection &isect, Amg::Vector3D &fieldValue, double &stepLength, const double qOverP, MagField::AtlasFieldCache &fieldCache) const
void assignStepLength(const TrackSurfaceIntersection &isect, double &stepLength) const
double distanceToPlane(const TrackSurfaceIntersection &isect, const Amg::Vector3D &planePosition, const Amg::Vector3D &planeNormal, double &stepLength) const
std::atomic< unsigned long long > m_countStepReduction
double distanceToLine(const TrackSurfaceIntersection &isect, const Amg::Vector3D &linePosition, const Amg::Vector3D &lineDirection, double &stepLength) const
std::atomic< unsigned long long > m_countStep
virtual std::optional< TrackSurfaceIntersection > approachStraightLineSurface(const StraightLineSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : StraightLineSurface.
RungeKuttaIntersector(const std::string &type, const std::string &name, const IInterface *parent)
double distanceToCylinder(const TrackSurfaceIntersection &isect, const double cylinderRadius, const double offsetRadius, const Amg::Vector3D &offset, double &stepLength) const
double distanceToDisc(const TrackSurfaceIntersection &isect, const double discZ, double &stepLength) const
std::atomic< unsigned long long > m_countExtrapolations
virtual std::optional< TrackSurfaceIntersection > intersectPlaneSurface(const PlaneSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PlaneSurface.
virtual std::optional< TrackSurfaceIntersection > intersectSurface(const Surface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for general Surface type.
void initializeFieldCache(MagField::AtlasFieldCache &fieldCache) const
std::atomic< unsigned long long > m_countShortStep
virtual std::optional< TrackSurfaceIntersection > intersectCylinderSurface(const CylinderSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : CylinderSurface.
virtual StatusCode finalize() override
void shortStep(TrackSurfaceIntersection &isect, const Amg::Vector3D &fieldValue, const double stepLength, const double qOverP) const
Amg::Vector3D field(const Amg::Vector3D &point, MagField::AtlasFieldCache &fieldCache) const
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
Abstract Base Class for tracking surfaces.
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
virtual constexpr SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
virtual const Amg::Vector3D & globalReferencePoint() const
Returns a global reference point on the surface, for PlaneSurface, StraightLineSurface,...
const Amg::Vector3D & center() const
Returns the center position of the Surface.
An intersection with a Surface is given by.
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
const Amg::Vector3D & position() const
Method to retrieve the position of the Intersection.
double pathlength() const
Method to retrieve the pathlength propagated till the Intersection.
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
@ qOverP
perigee
Definition ParamDefs.h:67
@ phi
Definition ParamDefs.h:75
MsgStream & msg
Definition testRead.cxx:32