Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
22 namespace{
23 
24 bool
25 isTrapped(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
47 namespace Trk
48 {
49 
51  const std::string& name,
52  const IInterface* parent)
53  : base_class (type, name, parent) {}
54 
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){
72  m_stepsUntilTrapped = 20000;
73  }
74 
75  return StatusCode::SUCCESS;
76 }
77 
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 
100 std::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 
141 std::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 
183 std::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 
225 std::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 
297 std::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 
338 std::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 
381 void
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 
584 void
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 
683 void
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 
710 void
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
RungeKuttaIntersector.h
Trk::RungeKuttaIntersector::m_muonZ0
const double m_muonZ0
Definition: RungeKuttaIntersector.h:170
Trk::RungeKuttaIntersector::distanceToPlane
double distanceToPlane(const TrackSurfaceIntersection &isect, const Amg::Vector3D &planePosition, const Amg::Vector3D &planeNormal, double &stepLength) const
Definition: RungeKuttaIntersector.h:266
python.AtlRunQueryAMI.period
period
Definition: AtlRunQueryAMI.py:225
Trk::RungeKuttaIntersector::m_toroidR2
const double m_toroidR2
Definition: RungeKuttaIntersector.h:189
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
Trk::RungeKuttaIntersector::m_momentumWarnThreshold
const double m_momentumWarnThreshold
Definition: RungeKuttaIntersector.h:166
GeV
#define GeV
Definition: PhysicsAnalysis/TauID/TauAnalysisTools/Root/HelperFunctions.cxx:17
Trk::RungeKuttaIntersector::m_countStepReduction
std::atomic< unsigned long long > m_countStepReduction
Definition: RungeKuttaIntersector.h:215
StraightLineSurface.h
TrackParameters.h
Trk::RungeKuttaIntersector::m_inDetR1
const double m_inDetR1
Definition: RungeKuttaIntersector.h:154
PerigeeSurface.h
Surface.h
Trk::RungeKuttaIntersector::m_third
const double m_third
Definition: RungeKuttaIntersector.h:183
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:44
Trk::RungeKuttaIntersector::m_stepMax1
double m_stepMax1
Definition: RungeKuttaIntersector.h:178
Trk::PerigeeSurface
Definition: PerigeeSurface.h:43
Trk::RungeKuttaIntersector::m_caloR2
const double m_caloR2
Definition: RungeKuttaIntersector.h:138
Trk::RungeKuttaIntersector::m_countExtrapolations
std::atomic< unsigned long long > m_countExtrapolations
Definition: RungeKuttaIntersector.h:212
Trk::RungeKuttaIntersector::m_productionMode
BooleanProperty m_productionMode
Definition: RungeKuttaIntersector.h:130
Trk::RungeKuttaIntersector::finalize
virtual StatusCode finalize() override
Definition: RungeKuttaIntersector.cxx:79
Trk::RungeKuttaIntersector::m_toroidZ6
const double m_toroidZ6
Definition: RungeKuttaIntersector.h:205
Trk::RungeKuttaIntersector::intersectPlaneSurface
virtual std::optional< TrackSurfaceIntersection > intersectPlaneSurface(const PlaneSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PlaneSurface.
Definition: RungeKuttaIntersector.cxx:339
Trk::RungeKuttaIntersector::m_inDetZ2
const double m_inDetZ2
Definition: RungeKuttaIntersector.h:162
Trk::RungeKuttaIntersector::m_toroidZ8
const double m_toroidZ8
Definition: RungeKuttaIntersector.h:209
Trk::RungeKuttaIntersector::initialize
virtual StatusCode initialize() override
Definition: RungeKuttaIntersector.cxx:56
Trk::RungeKuttaIntersector::distanceToCylinder
double distanceToCylinder(const TrackSurfaceIntersection &isect, const double cylinderRadius, const double offsetRadius, const Amg::Vector3D &offset, double &stepLength) const
Definition: RungeKuttaIntersector.h:220
Trk::RungeKuttaIntersector::m_stepsUntilTrapped
int m_stepsUntilTrapped
Definition: RungeKuttaIntersector.h:182
Trk::RungeKuttaIntersector::m_stepMax4
double m_stepMax4
Definition: RungeKuttaIntersector.h:181
test_pyathena.pt
pt
Definition: test_pyathena.py:11
M_PI
#define M_PI
Definition: ActiveFraction.h:11
Trk::RungeKuttaIntersector::m_toroidR3
const double m_toroidR3
Definition: RungeKuttaIntersector.h:191
Trk::RungeKuttaIntersector::RungeKuttaIntersector
RungeKuttaIntersector(const std::string &type, const std::string &name, const IInterface *parent)
Definition: RungeKuttaIntersector.cxx:50
Trk::RungeKuttaIntersector::m_shortStepMax
double m_shortStepMax
Definition: RungeKuttaIntersector.h:171
Trk::TrackSurfaceIntersection
Definition: TrackSurfaceIntersection.h:32
Trk::RungeKuttaIntersector::field
Amg::Vector3D field(const Amg::Vector3D &point, MagField::AtlasFieldCache &fieldCache) const
Definition: RungeKuttaIntersector.h:291
Trk::DiscSurface
Definition: DiscSurface.h:54
Trk::Surface::globalReferencePoint
virtual const Amg::Vector3D & globalReferencePoint() const
Returns a global reference point on the surface, for PlaneSurface, StraightLineSurface,...
Trk::TrackSurfaceIntersection::pathlength
double pathlength() const
Method to retrieve the pathlength propagated till the Intersection.
Definition: TrackSurfaceIntersection.h:96
xAOD::P4Helpers::deltaR2
double deltaR2(double rapidity1, double phi1, double rapidity2, double phi2)
from bare rapidity,phi
Definition: xAODP4Helpers.h:111
Trk::Surface::center
const Amg::Vector3D & center() const
Returns the center position of the Surface.
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
Trk::RungeKuttaIntersector::m_caloR4
const double m_caloR4
Definition: RungeKuttaIntersector.h:142
Trk::RungeKuttaIntersector::m_caloR0
const double m_caloR0
Definition: RungeKuttaIntersector.h:134
Trk::RungeKuttaIntersector::m_stepMax2
double m_stepMax2
Definition: RungeKuttaIntersector.h:179
Trk::RungeKuttaIntersector::m_momentumThreshold
const double m_momentumThreshold
Definition: RungeKuttaIntersector.h:164
Trk::RungeKuttaIntersector::m_caloR1
const double m_caloR1
Definition: RungeKuttaIntersector.h:136
Trk::RungeKuttaIntersector::m_stepMax3
double m_stepMax3
Definition: RungeKuttaIntersector.h:180
Trk::RungeKuttaIntersector::m_toroidZ3
const double m_toroidZ3
Definition: RungeKuttaIntersector.h:199
Trk::RungeKuttaIntersector::m_toroidZ7
const double m_toroidZ7
Definition: RungeKuttaIntersector.h:207
Trk::RungeKuttaIntersector::m_solenoidZ
const double m_solenoidZ
Definition: RungeKuttaIntersector.h:176
StdJOSetup.msgSvc
msgSvc
Provide convenience handles for various services.
Definition: StdJOSetup.py:36
Trk::RungeKuttaIntersector::m_caloR3
const double m_caloR3
Definition: RungeKuttaIntersector.h:140
Trk::RungeKuttaIntersector::distanceToDisc
double distanceToDisc(const TrackSurfaceIntersection &isect, const double discZ, double &stepLength) const
Definition: RungeKuttaIntersector.h:236
Trk::TrackSurfaceIntersection::position
const Amg::Vector3D & position() const
Method to retrieve the position of the Intersection.
Definition: TrackSurfaceIntersection.h:80
Trk::RungeKuttaIntersector::m_toroidR1
const double m_toroidR1
Definition: RungeKuttaIntersector.h:187
Trk::RungeKuttaIntersector::m_caloZ2
const double m_caloZ2
Definition: RungeKuttaIntersector.h:148
beamspotman.n
n
Definition: beamspotman.py:731
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Trk::CylinderSurface
Definition: CylinderSurface.h:55
Trk::RungeKuttaIntersector::step
void step(TrackSurfaceIntersection &isect, Amg::Vector3D &fieldValue, double &stepLength, const double qOverP, MagField::AtlasFieldCache &fieldCache) const
Definition: RungeKuttaIntersector.cxx:711
Trk::RungeKuttaIntersector::shortStep
void shortStep(TrackSurfaceIntersection &isect, const Amg::Vector3D &fieldValue, const double stepLength, const double qOverP) const
Definition: RungeKuttaIntersector.cxx:684
CylinderSurface.h
test_pyathena.parent
parent
Definition: test_pyathena.py:15
Trk::RungeKuttaIntersector::distanceToLine
double distanceToLine(const TrackSurfaceIntersection &isect, const Amg::Vector3D &linePosition, const Amg::Vector3D &lineDirection, double &stepLength) const
Definition: RungeKuttaIntersector.h:247
Trk::Surface::normal
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Trk::RungeKuttaIntersector::initializeFieldCache
void initializeFieldCache(MagField::AtlasFieldCache &fieldCache) const
Definition: RungeKuttaIntersector.h:280
Trk::RungeKuttaIntersector::m_caloZ1
const double m_caloZ1
Definition: RungeKuttaIntersector.h:146
Trk::RungeKuttaIntersector::m_countShortStep
std::atomic< unsigned long long > m_countShortStep
Definition: RungeKuttaIntersector.h:213
python.SystemOfUnits.nanometer
int nanometer
Definition: SystemOfUnits.py:72
Trk::RungeKuttaIntersector::m_toroidZ5
const double m_toroidZ5
Definition: RungeKuttaIntersector.h:203
beamspotman.dir
string dir
Definition: beamspotman.py:623
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::SurfaceType::Perigee
@ Perigee
Trk::RungeKuttaIntersector::m_inDetZ1
const double m_inDetZ1
Definition: RungeKuttaIntersector.h:160
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
Trk::RungeKuttaIntersector::m_muonR0
const double m_muonR0
Definition: RungeKuttaIntersector.h:168
Trk::RungeKuttaIntersector::assignStepLength
void assignStepLength(const TrackSurfaceIntersection &isect, double &stepLength) const
Definition: RungeKuttaIntersector.cxx:382
Trk::RungeKuttaIntersector::m_fieldCacheCondObjInputKey
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
Definition: RungeKuttaIntersector.h:125
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
Trk::RungeKuttaIntersector::m_solenoidR
const double m_solenoidR
Definition: RungeKuttaIntersector.h:174
python.PhysicalConstants.c_light
float c_light
Definition: PhysicalConstants.py:63
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
query_example.col
col
Definition: query_example.py:7
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
Trk::TrackSurfaceIntersection::direction
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
Definition: TrackSurfaceIntersection.h:88
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
Trk::RungeKuttaIntersector::m_inDetZ0
const double m_inDetZ0
Definition: RungeKuttaIntersector.h:158
taskman.fieldValue
fieldValue
Definition: taskman.py:493
Trk::RungeKuttaIntersector::intersectCylinderSurface
virtual std::optional< TrackSurfaceIntersection > intersectCylinderSurface(const CylinderSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : CylinderSurface.
Definition: RungeKuttaIntersector.cxx:226
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::PlaneSurface
Definition: PlaneSurface.h:64
Trk::RungeKuttaIntersector::m_toroidR0
const double m_toroidR0
Definition: RungeKuttaIntersector.h:185
PlaneSurface.h
Trk::RungeKuttaIntersector::m_caloZ3
const double m_caloZ3
Definition: RungeKuttaIntersector.h:150
DEBUG
#define DEBUG
Definition: page_access.h:11
MagField::AtlasFieldCache
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Definition: AtlasFieldCache.h:43
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
Trk::SurfaceType::Disc
@ Disc
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
Trk::RungeKuttaIntersector::m_inDetR0
const double m_inDetR0
Definition: RungeKuttaIntersector.h:152
Trk::SurfaceType::Cylinder
@ Cylinder
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
DiscSurface.h
Trk::RungeKuttaIntersector::m_caloZ0
const double m_caloZ0
Definition: RungeKuttaIntersector.h:144
Trk::RungeKuttaIntersector::m_toroidZ4
const double m_toroidZ4
Definition: RungeKuttaIntersector.h:201
Trk::SurfaceType::Plane
@ Plane
Trk::phi
@ phi
Definition: ParamDefs.h:75
Trk::RungeKuttaIntersector::m_stepMax0
double m_stepMax0
Definition: RungeKuttaIntersector.h:177
Trk::RungeKuttaIntersector::intersectSurface
virtual std::optional< TrackSurfaceIntersection > intersectSurface(const Surface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for general Surface type.
Definition: RungeKuttaIntersector.cxx:101
Trk::RungeKuttaIntersector::approachPerigeeSurface
virtual std::optional< TrackSurfaceIntersection > approachPerigeeSurface(const PerigeeSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : PerigeeSurface.
Definition: RungeKuttaIntersector.cxx:142
Trk::RungeKuttaIntersector::m_countStep
std::atomic< unsigned long long > m_countStep
Definition: RungeKuttaIntersector.h:214
Trk::RungeKuttaIntersector::approachStraightLineSurface
virtual std::optional< TrackSurfaceIntersection > approachStraightLineSurface(const StraightLineSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : StraightLineSurface.
Definition: RungeKuttaIntersector.cxx:184
Trk::SurfaceType::Line
@ Line
Trk::RungeKuttaIntersector::m_inDetR2
const double m_inDetR2
Definition: RungeKuttaIntersector.h:156
Trk::CylinderSurface::globalReferencePoint
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...
Definition: CylinderSurface.cxx:167
Trk::RungeKuttaIntersector::intersectDiscSurface
virtual std::optional< TrackSurfaceIntersection > intersectDiscSurface(const DiscSurface &surface, const TrackSurfaceIntersection &trackIntersection, const double qOverP) const override
IIntersector interface method for specific Surface type : DiscSurface.
Definition: RungeKuttaIntersector.cxx:298
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Trk::RungeKuttaIntersector::newIntersection
std::optional< TrackSurfaceIntersection > newIntersection(TrackSurfaceIntersection &&isect, const Surface &surface, const double qOverP, const double rStart, const double zStart) const
Definition: RungeKuttaIntersector.h:299
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
Trk::RungeKuttaIntersector::m_toroidZ2
const double m_toroidZ2
Definition: RungeKuttaIntersector.h:197
Trk::Surface::transform
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Intersection.h
Trk::RungeKuttaIntersector::m_shortStepMin
const double m_shortStepMin
Definition: RungeKuttaIntersector.h:172
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Trk::Surface::type
constexpr virtual SurfaceType type() const =0
Returns the Surface type to avoid dynamic casts.
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
Trk::RungeKuttaIntersector::m_toroidZ1
const double m_toroidZ1
Definition: RungeKuttaIntersector.h:195
Trk::StraightLineSurface
Definition: StraightLineSurface.h:51
Trk::RungeKuttaIntersector::debugFailure
void debugFailure(TrackSurfaceIntersection &&isect, const Surface &surface, const double qOverP, const double rStart, const double zStart, const bool trapped) const
Definition: RungeKuttaIntersector.cxx:585