Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveTrackPropagator.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007, 2018
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
13 #include <ROOT/REveTrack.hxx>
14 #include <ROOT/REveTrans.hxx>
15 
16 #include "TMath.h"
17 
18 using namespace ROOT::Experimental;
19 namespace REX = ROOT::Experimental;
20 
21 /** \class REveMagField
22 \ingroup REve
23 Abstract base-class for interfacing to magnetic field needed by the
24 REveTrackPropagator.
25 See sub-classes for two simple implementations.
26 
27 NOTE: Magnetic field direction convention is inverted.
28 */
29 
30 
31 /** \class REveMagFieldConst
32 \ingroup REve
33 Implements constant magnetic field, given by a vector fB.
34 
35 NOTE: Magnetic field direction convention is inverted.
36 */
37 
38 
39 /** \class REveMagFieldDuo
40 \ingroup REve
41 Implements constant magnetic filed that switches on given axial radius fR2
42 from vector fBIn to fBOut.
43 
44 NOTE: Magnetic field direction convention is inverted.
45 */
46 
47 namespace
48 {
49  //const Double_t kBMin = 1e-6;
50  const Double_t kPtMinSqr = 1e-20;
51  const Double_t kAMin = 1e-10;
52  const Double_t kStepEps = 1e-3;
53 }
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// Default constructor.
57 
58 REveTrackPropagator::Helix_t::Helix_t() :
59  fCharge(0),
60  fMaxAng(45), fMaxStep(20.f), fDelta(0.1),
61  fPhi(0), fValid(kFALSE),
62  fLam(-1), fR(-1), fPhiStep(-1), fSin(-1), fCos(-1),
63  fRKStep(20.0),
64  fPtMag(-1), fPlMag(-1), fLStep(-1)
65 {
66 }
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 /// Common update code for helix and RK propagation.
70 
71 void REveTrackPropagator::Helix_t::UpdateCommon(const REveVectorD& p, const REveVectorD& b)
72 {
73  fB = b;
74 
75  // base vectors
76  fE1 = b;
77  fE1.Normalize();
78  fPlMag = p.Dot(fE1);
79  fPl = fE1*fPlMag;
80 
81  fPt = p - fPl;
82  fPtMag = fPt.Mag();
83  fE2 = fPt;
84  fE2.Normalize();
85 }
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 /// Update helix parameters.
89 
90 void REveTrackPropagator::Helix_t::UpdateHelix(const REveVectorD& p, const REveVectorD& b,
91  Bool_t full_update, Bool_t enforce_max_step)
92 {
93  UpdateCommon(p, b);
94 
95  // helix parameters
96  TMath::Cross(fE1.Arr(), fE2.Arr(), fE3.Arr());
97  if (fCharge < 0) fE3.NegateXYZ();
98 
99  if (full_update)
100  {
101  using namespace TMath;
102  Double_t a = fgkB2C * b.Mag() * Abs(fCharge);
103  if (a > kAMin && fPtMag*fPtMag > kPtMinSqr)
104  {
105  fValid = kTRUE;
106 
107  fR = Abs(fPtMag / a);
108  fLam = fPlMag / fPtMag;
109 
110  // get phi step, compare fMaxAng with fDelta
111  fPhiStep = fMaxAng * DegToRad();
112  if (fR > fDelta)
113  {
114  Double_t ang = 2.0 * ACos(1.0f - fDelta/fR);
115  if (ang < fPhiStep)
116  fPhiStep = ang;
117  }
118 
119  // check max step size
120  Double_t curr_step = fR * fPhiStep * Sqrt(1.0f + fLam*fLam);
121  if (curr_step > fMaxStep || enforce_max_step)
122  fPhiStep *= fMaxStep / curr_step;
123 
124  fLStep = fR * fPhiStep * fLam;
125  fSin = Sin(fPhiStep);
126  fCos = Cos(fPhiStep);
127  }
128  else
129  {
130  fValid = kFALSE;
131  }
132  }
133 }
134 
135 ////////////////////////////////////////////////////////////////////////////////
136 /// Update helix for stepper RungeKutta.
137 
138 void REveTrackPropagator::Helix_t::UpdateRK(const REveVectorD& p, const REveVectorD& b)
139 {
140  UpdateCommon(p, b);
141 
142  if (fCharge)
143  {
144  fValid = kTRUE;
145 
146  // cached values for propagator
147  fB = b;
148  fPlMag = p.Dot(fB);
149  }
150  else
151  {
152  fValid = kFALSE;
153  }
154 }
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 /// Step helix for given momentum p from vertex v.
158 
159 void REveTrackPropagator::Helix_t::Step(const REveVector4D& v, const REveVectorD& p,
160  REveVector4D& vOut, REveVectorD& pOut)
161 {
162  vOut = v;
163 
164  if (fValid)
165  {
166  REveVectorD d = fE2*(fR*fSin) + fE3*(fR*(1-fCos)) + fE1*fLStep;
167  vOut += d;
168  vOut.fT += TMath::Abs(fLStep);
169 
170  pOut = fPl + fE2*(fPtMag*fCos) + fE3*(fPtMag*fSin);
171 
172  fPhi += fPhiStep;
173  }
174  else
175  {
176  // case: pT < kPtMinSqr or B < kBMin
177  // might happen if field directon changes pT ~ 0 or B becomes zero
178  vOut += p * (fMaxStep / p.Mag());
179  vOut.fT += fMaxStep;
180  pOut = p;
181  }
182 }
183 
184 /** \class REveTrackPropagator
185 \ingroup REve
186 Holding structure for a number of track rendering parameters.
187 Calculates path taking into account the parameters.
188 
189 NOTE: Magnetic field direction convention is inverted.
190 
191 This is decoupled from REveTrack/REveTrackList to allow sharing of the
192 Propagator among several instances. Back references are kept so the tracks
193 can be recreated when the parameters change.
194 
195 REveTrackList has Get/Set methods for RnrStlye.
196 
197 Enum EProjTrackBreaking_e and member fProjTrackBreaking specify whether 2D
198 projected tracks get broken into several segments when the projected space
199 consists of separate domains (like Rho-Z). The track-breaking is enabled by
200 default.
201 */
202 
203 Double_t REveTrackPropagator::fgDefMagField = 0.5;
204 const Double_t REveTrackPropagator::fgkB2C = 0.299792458e-2;
205 REveTrackPropagator REveTrackPropagator::fgDefault;
206 
207 Double_t REveTrackPropagator::fgEditorMaxR = 2000;
208 Double_t REveTrackPropagator::fgEditorMaxZ = 4000;
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 /// Default constructor.
212 
213 REveTrackPropagator::REveTrackPropagator(const std::string& n, const std::string& t,
214  REveMagField *field, Bool_t own_field) :
215  REveElement(n, t),
216  REveRefBackPtr(),
217 
218  fStepper(kHelix),
219  fMagFieldObj(field),
220  fOwnMagFiledObj(own_field),
221 
222  fMaxR (350), fMaxZ (450),
223  fNMax (4096), fMaxOrbs (0.5),
224 
225  fEditPathMarks (kTRUE),
226  fFitDaughters (kTRUE), fFitReferences (kTRUE),
227  fFitDecay (kTRUE),
228  fFitCluster2Ds (kTRUE), fFitLineSegments (kTRUE),
229  fRnrDaughters (kFALSE), fRnrReferences (kFALSE),
230  fRnrDecay (kFALSE), fRnrCluster2Ds (kFALSE),
231  fRnrFV (kFALSE),
232  fPMAtt(), fFVAtt(),
233 
234  fProjTrackBreaking(kPTB_Break), fRnrPTBMarkers(kFALSE), fPTBAtt(),
235 
236  fV()
237 {
238  fPMAtt.SetMarkerColor(kYellow);
239  fPMAtt.SetMarkerStyle(2);
240  fPMAtt.SetMarkerSize(2);
241 
242  fFVAtt.SetMarkerColor(kRed);
243  fFVAtt.SetMarkerStyle(4);
244  fFVAtt.SetMarkerSize(1.5);
245 
246  fPTBAtt.SetMarkerColor(kBlue);
247  fPTBAtt.SetMarkerStyle(4);
248  fPTBAtt.SetMarkerSize(0.8);
249 
250  if (!fMagFieldObj) {
251  fMagFieldObj = new REveMagFieldConst(0., 0., fgDefMagField);
252  fOwnMagFiledObj = kTRUE;
253  }
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 /// Destructor.
258 
259 REveTrackPropagator::~REveTrackPropagator()
260 {
261  if (fOwnMagFiledObj)
262  {
263  delete fMagFieldObj;
264  }
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Virtual from REveRefBackPtr - track reference count has reached zero.
269 
270 void REveTrackPropagator::OnZeroRefCount()
271 {
272  CheckReferenceCount("REveTrackPropagator::OnZeroRefCount ");
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// Check reference count - virtual from REveElement.
277 /// Must also take into account references from REveRefBackPtr.
278 
279 void REveTrackPropagator::CheckReferenceCount(const std::string& from)
280 {
281  if (fRefCount <= 0)
282  {
283  REveElement::CheckReferenceCount(from);
284  }
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 /// Element-change notification.
289 /// Stamp all tracks as requiring display-list regeneration.
290 
291 void REveTrackPropagator::StampAllTracks()
292 {
293  for (auto &i: fBackRefs) {
294  auto track = dynamic_cast<REveTrack *>(i.first);
295  if (track) track->StampObjProps();
296  }
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Initialize internal data-members for given particle parameters.
301 
302 void REveTrackPropagator::InitTrack(const REveVectorD &v, Int_t charge)
303 {
304  fV = v;
305  fPoints.push_back(fV);
306 
307  // init helix
308  fH.fPhi = 0;
309  fH.fCharge = charge;
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// REveVectorF wrapper.
314 
315 void REveTrackPropagator::InitTrack(const REveVectorF& v, Int_t charge)
316 {
317  REveVectorD vd(v);
318  InitTrack(vd, charge);
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Reset cache holding particle trajectory.
323 
324 void REveTrackPropagator::ResetTrack()
325 {
326  fLastPoints.clear();
327  fPoints.swap(fLastPoints);
328 
329  // reset helix
330  fH.fPhi = 0;
331 }
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Get index of current point on track.
335 
336 Int_t REveTrackPropagator::GetCurrentPoint() const
337 {
338  return fPoints.size() - 1;
339 }
340 
341 ////////////////////////////////////////////////////////////////////////////////
342 /// Calculate track length from start_point to end_point.
343 /// If end_point is less than 0, distance to the end is returned.
344 
345 Double_t REveTrackPropagator::GetTrackLength(Int_t start_point, Int_t end_point) const
346 {
347  if (end_point < 0) end_point = fPoints.size() - 1;
348 
349  Double_t sum = 0;
350  for (Int_t i = start_point; i < end_point; ++i)
351  {
352  sum += (fPoints[i+1] - fPoints[i]).Mag();
353  }
354  return sum;
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Propagate particle with momentum p to vertex v.
359 
360 Bool_t REveTrackPropagator::GoToVertex(REveVectorD& v, REveVectorD& p)
361 {
362  Update(fV, p, kTRUE);
363 
364  if ((v-fV).Mag() < kStepEps)
365  {
366  fPoints.push_back(v);
367  return kTRUE;
368  }
369 
370  return fH.fValid ? LoopToVertex(v, p) : LineToVertex(v);
371 }
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 /// Propagate particle with momentum p to line with start point s and vector r
375 /// to the second point.
376 
377 Bool_t REveTrackPropagator::GoToLineSegment(const REveVectorD& s, const REveVectorD& r, REveVectorD& p)
378 {
379  Update(fV, p, kTRUE);
380 
381  if (!fH.fValid)
382  {
383  REveVectorD v;
384  ClosestPointBetweenLines(s, r, fV, p, v);
385  LineToVertex(v);
386  return kTRUE;
387  }
388  else
389  {
390  return LoopToLineSegment(s, r, p);
391  }
392 }
393 
394 ////////////////////////////////////////////////////////////////////////////////
395 /// REveVectorF wrapper.
396 
397 Bool_t REveTrackPropagator::GoToVertex(REveVectorF& v, REveVectorF& p)
398 {
399  REveVectorD vd(v), pd(p);
400  Bool_t result = GoToVertex(vd, pd);
401  v = vd; p = pd;
402  return result;
403 }
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 /// REveVectorF wrapper.
407 
408 Bool_t REveTrackPropagator::GoToLineSegment(const REveVectorF& s, const REveVectorF& r, REveVectorF& p)
409 {
410  REveVectorD sd(s), rd(r), pd(p);
411  Bool_t result = GoToLineSegment(sd, rd, pd);
412  p = pd;
413  return result;
414 }
415 
416 ////////////////////////////////////////////////////////////////////////////////
417 /// Propagate particle to bounds.
418 /// Return TRUE if hit bounds.
419 
420 void REveTrackPropagator::GoToBounds(REveVectorD& p)
421 {
422  Update(fV, p, kTRUE);
423 
424  fH.fValid ? LoopToBounds(p): LineToBounds(p);
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// REveVectorF wrapper.
429 
430 void REveTrackPropagator::GoToBounds(REveVectorF& p)
431 {
432  REveVectorD pd(p);
433  GoToBounds(pd);
434  p = pd;
435 }
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Update helix / B-field projection state.
439 
440 void REveTrackPropagator::Update(const REveVector4D& v, const REveVectorD& p,
441  Bool_t full_update, Bool_t enforce_max_step)
442 {
443  if (fStepper == kHelix)
444  {
445  fH.UpdateHelix(p, fMagFieldObj->GetFieldD(v), !fMagFieldObj->IsConst() || full_update, enforce_max_step);
446  }
447  else
448  {
449  fH.UpdateRK(p, fMagFieldObj->GetFieldD(v));
450 
451  if (full_update)
452  {
453  using namespace TMath;
454 
455  Float_t a = fgkB2C * fMagFieldObj->GetMaxFieldMagD() * Abs(fH.fCharge);
456  if (a > kAMin)
457  {
458  fH.fR = p.Mag() / a;
459 
460  // get phi step, compare fDelta with MaxAng
461  fH.fPhiStep = fH.fMaxAng * DegToRad();
462  if (fH.fR > fH.fDelta )
463  {
464  Double_t ang = 2.0 * ACos(1.0f - fH.fDelta/fH.fR);
465  if (ang < fH.fPhiStep)
466  fH.fPhiStep = ang;
467  }
468 
469  // check against maximum step-size
470  fH.fRKStep = fH.fR * fH.fPhiStep * Sqrt(1 + fH.fLam*fH.fLam);
471  if (fH.fRKStep > fH.fMaxStep || enforce_max_step)
472  {
473  fH.fPhiStep *= fH.fMaxStep / fH.fRKStep;
474  fH.fRKStep = fH.fMaxStep;
475  }
476  }
477  else
478  {
479  fH.fRKStep = fH.fMaxStep;
480  }
481  }
482  }
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// Wrapper to step helix.
487 
488 void REveTrackPropagator::Step(const REveVector4D &v, const REveVectorD &p, REveVector4D &vOut, REveVectorD &pOut)
489 {
490  if (fStepper == kHelix)
491  {
492  fH.Step(v, p, vOut, pOut);
493  }
494  else
495  {
496  Double_t vecRKIn[7];
497  vecRKIn[0] = v.fX;
498  vecRKIn[1] = v.fY;
499  vecRKIn[2] = v.fZ;
500  Double_t pm = p.Mag();
501  Double_t nm = 1.0 / pm;
502  vecRKIn[3] = p.fX*nm;
503  vecRKIn[4] = p.fY*nm;
504  vecRKIn[5] = p.fZ*nm;
505  vecRKIn[6] = p.Mag();
506 
507  Double_t vecRKOut[7];
508  StepRungeKutta(fH.fRKStep, vecRKIn, vecRKOut);
509 
510  vOut.fX = vecRKOut[0];
511  vOut.fY = vecRKOut[1];
512  vOut.fZ = vecRKOut[2];
513  vOut.fT = v.fT + fH.fRKStep;
514  pm = vecRKOut[6];
515  pOut.fX = vecRKOut[3]*pm;
516  pOut.fY = vecRKOut[4]*pm;
517  pOut.fZ = vecRKOut[5]*pm;
518  }
519 }
520 
521 ////////////////////////////////////////////////////////////////////////////////
522 /// Propagate charged particle with momentum p to bounds.
523 /// It is expected that Update() with full-update was called before.
524 
525 void REveTrackPropagator::LoopToBounds(REveVectorD& p)
526 {
527  const Double_t maxRsq = fMaxR*fMaxR;
528 
529  REveVector4D currV(fV);
530  REveVector4D forwV(fV);
531  REveVectorD forwP (p);
532 
533  Int_t np = fPoints.size();
534  Double_t maxPhi = fMaxOrbs*TMath::TwoPi();
535 
536  while (fH.fPhi < maxPhi && np<fNMax)
537  {
538  Step(currV, p, forwV, forwP);
539 
540  // cross R
541  if (forwV.Perp2() > maxRsq)
542  {
543  Float_t t = (fMaxR - currV.R()) / (forwV.R() - currV.R());
544  if (t < 0 || t > 1)
545  {
546  Warning("HelixToBounds", "In MaxR crossing expected t>=0 && t<=1: t=%f, r1=%f, r2=%f, MaxR=%f.",
547  t, currV.R(), forwV.R(), fMaxR);
548  return;
549  }
550  REveVectorD d(forwV);
551  d -= currV;
552  d *= t;
553  d += currV;
554  fPoints.push_back(d);
555  return;
556  }
557 
558  // cross Z
559  else if (TMath::Abs(forwV.fZ) > fMaxZ)
560  {
561  Double_t t = (fMaxZ - TMath::Abs(currV.fZ)) / TMath::Abs((forwV.fZ - currV.fZ));
562  if (t < 0 || t > 1)
563  {
564  Warning("HelixToBounds", "In MaxZ crossing expected t>=0 && t<=1: t=%f, z1=%f, z2=%f, MaxZ=%f.",
565  t, currV.fZ, forwV.fZ, fMaxZ);
566  return;
567  }
568  REveVectorD d(forwV -currV);
569  d *= t;
570  d += currV;
571  fPoints.push_back(d);
572  return;
573  }
574 
575  currV = forwV;
576  p = forwP;
577  Update(currV, p);
578 
579  fPoints.push_back(currV);
580  ++np;
581  }
582 }
583 
584 ////////////////////////////////////////////////////////////////////////////////
585 /// Propagate charged particle with momentum p to vertex v.
586 /// It is expected that Update() with full-update was called before.
587 
588 Bool_t REveTrackPropagator::LoopToVertex(REveVectorD& v, REveVectorD& p)
589 {
590  const Double_t maxRsq = fMaxR * fMaxR;
591 
592  REveVector4D currV(fV);
593  REveVector4D forwV(fV);
594  REveVectorD forwP(p);
595 
596  Int_t first_point = fPoints.size();
597  Int_t np = first_point;
598 
599  Double_t prod0=0, prod1;
600 
601  do
602  {
603  Step(currV, p, forwV, forwP);
604  Update(forwV, forwP);
605 
606  if (PointOverVertex(v, forwV, &prod1))
607  {
608  break;
609  }
610 
611  if (IsOutsideBounds(forwV, maxRsq, fMaxZ))
612  {
613  fV = currV;
614  return kFALSE;
615  }
616 
617  fPoints.push_back(forwV);
618  currV = forwV;
619  p = forwP;
620  prod0 = prod1;
621  ++np;
622  } while (np < fNMax);
623 
624  // make the remaining fractional step
625  if (np > first_point)
626  {
627  if ((v - currV).Mag() > kStepEps)
628  {
629  Double_t step_frac = prod0 / (prod0 - prod1);
630  if (step_frac > 0)
631  {
632  // Step for fraction of previous step size.
633  // We pass 'enforce_max_step' flag to Update().
634  Float_t orig_max_step = fH.fMaxStep;
635  fH.fMaxStep = step_frac * (forwV - currV).Mag();
636  Update(currV, p, kTRUE, kTRUE);
637  Step(currV, p, forwV, forwP);
638  p = forwP;
639  currV = forwV;
640  fPoints.push_back(currV);
641  ++np;
642  fH.fMaxStep = orig_max_step;
643  }
644 
645  // Distribute offset to desired crossing point over all segment.
646 
647  REveVectorD off(v - currV);
648  off *= 1.0f / currV.fT;
649  DistributeOffset(off, first_point, np, p);
650  fV = v;
651  return kTRUE;
652  }
653  }
654 
655  fPoints.push_back(v);
656  fV = v;
657  return kTRUE;
658 }
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 /// Propagate charged particle with momentum p to line segment with point s and
662 /// vector r to the second point. It is expected that Update() with full-update
663 /// was called before. Returns kFALSE if hits bounds.
664 
665 Bool_t REveTrackPropagator::LoopToLineSegment(const REveVectorD& s, const REveVectorD& r, REveVectorD& p)
666 {
667  const Double_t maxRsq = fMaxR * fMaxR;
668  const Double_t rMagInv = 1./r.Mag();
669 
670  REveVector4D currV(fV);
671  REveVector4D forwV(fV);
672  REveVectorD forwP(p);
673 
674  Int_t first_point = fPoints.size();
675  Int_t np = first_point;
676 
677  REveVectorD forwC;
678  REveVectorD currC;
679  do
680  {
681  Step(currV, p, forwV, forwP);
682  Update(forwV, forwP);
683 
684  ClosestPointFromVertexToLineSegment(forwV, s, r, rMagInv, forwC);
685 
686  // check forwV is over segment with orthogonal component of
687  // momentum to vector r
688  REveVectorD b = r; b.Normalize();
689  Double_t x = forwP.Dot(b);
690  REveVectorD pTPM = forwP - x*b;
691  if (pTPM.Dot(forwC - forwV) < 0)
692  {
693  break;
694  }
695 
696  if (IsOutsideBounds(forwV, maxRsq, fMaxZ))
697  {
698  fV = currV;
699  return kFALSE;
700  }
701 
702  fPoints.push_back(forwV);
703  currV = forwV;
704  p = forwP;
705  currC = forwC;
706  ++np;
707  } while (np < fNMax);
708 
709  // Get closest point on segment relative to line with forw and currV points.
710  REveVectorD v;
711  ClosestPointBetweenLines(s, r, currV, forwV - currV, v);
712 
713  // make the remaining fractional step
714  if (np > first_point)
715  {
716  if ((v - currV).Mag() > kStepEps)
717  {
718  REveVector last_step = forwV - currV;
719  REveVector delta = v - currV;
720  Double_t step_frac = last_step.Dot(delta) / last_step.Mag2();
721  if (step_frac > 0)
722  {
723  // Step for fraction of previous step size.
724  // We pass 'enforce_max_step' flag to Update().
725  Float_t orig_max_step = fH.fMaxStep;
726  fH.fMaxStep = step_frac * (forwV - currV).Mag();
727  Update(currV, p, kTRUE, kTRUE);
728  Step(currV, p, forwV, forwP);
729  p = forwP;
730  currV = forwV;
731  fPoints.push_back(currV);
732  ++np;
733  fH.fMaxStep = orig_max_step;
734  }
735 
736  // Distribute offset to desired crossing point over all segment.
737 
738  REveVectorD off(v - currV);
739  off *= 1.0f / currV.fT;
740  DistributeOffset(off, first_point, np, p);
741  fV = v;
742  return kTRUE;
743  }
744  }
745 
746  fPoints.push_back(v);
747  fV = v;
748  return kTRUE;
749 }
750 
751 ////////////////////////////////////////////////////////////////////////////////
752 /// Distribute offset between first and last point index and rotate
753 /// momentum.
754 
755 void REveTrackPropagator::DistributeOffset(const REveVectorD& off, Int_t first_point, Int_t np, REveVectorD& p)
756 {
757  // Calculate the required momentum rotation.
758  // lpd - last-points-delta
759  REveVectorD lpd0(fPoints[np-1]);
760  lpd0 -= fPoints[np-2];
761  lpd0.Normalize();
762 
763  for (Int_t i = first_point; i < np; ++i)
764  {
765  fPoints[i] += off * fPoints[i].fT;
766  }
767 
768  REveVectorD lpd1(fPoints[np-1]);
769  lpd1 -= fPoints[np-2];
770  lpd1.Normalize();
771 
772  REveTrans tt;
773  tt.SetupFromToVec(lpd0, lpd1);
774 
775  // REveVectorD pb4(p);
776  // printf("Rotating momentum: p0 = "); p.Dump();
777  tt.RotateIP(p);
778  // printf(" p1 = "); p.Dump();
779  // printf(" n1=%f, n2=%f, dp = %f deg\n", pb4.Mag(), p.Mag(),
780  // TMath::RadToDeg()*TMath::ACos(p.Dot(pb4)/(pb4.Mag()*p.Mag())));
781 }
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Propagate neutral particle to vertex v.
785 
786 Bool_t REveTrackPropagator::LineToVertex(REveVectorD& v)
787 {
788  REveVector4D currV = v;
789 
790  currV.fX = v.fX;
791  currV.fY = v.fY;
792  currV.fZ = v.fZ;
793  fPoints.push_back(currV);
794 
795  fV = v;
796  return kTRUE;
797 }
798 
799 ////////////////////////////////////////////////////////////////////////////////
800 /// Propagate neutral particle with momentum p to bounds.
801 
802 void REveTrackPropagator::LineToBounds(REveVectorD& p)
803 {
804  Double_t tZ = 0, tR = 0, tB = 0;
805 
806  // time where particle intersect +/- fMaxZ
807  if (p.fZ > 0)
808  tZ = (fMaxZ - fV.fZ) / p.fZ;
809  else if (p.fZ < 0)
810  tZ = - (fMaxZ + fV.fZ) / p.fZ;
811  else
812  tZ = 1e99;
813 
814  // time where particle intersects cylinder
815  Double_t a = p.fX*p.fX + p.fY*p.fY;
816  Double_t b = 2.0 * (fV.fX*p.fX + fV.fY*p.fY);
817  Double_t c = fV.fX*fV.fX + fV.fY*fV.fY - fMaxR*fMaxR;
818  Double_t d = b*b - 4.0*a*c;
819  if (d >= 0) {
820  Double_t sqrtD = TMath::Sqrt(d);
821  tR = (-b - sqrtD) / (2.0 * a);
822  if (tR < 0) {
823  tR = (-b + sqrtD) / (2.0 * a);
824  }
825  tB = tR < tZ ? tR : tZ; // compare the two times
826  } else {
827  tB = tZ;
828  }
829  REveVectorD nv(fV.fX + p.fX*tB, fV.fY + p.fY*tB, fV.fZ + p.fZ*tB);
830  LineToVertex(nv);
831 }
832 
833 ////////////////////////////////////////////////////////////////////////////////
834 /// Intersect helix with a plane. Current position and argument p define
835 /// the helix.
836 
837 Bool_t REveTrackPropagator::HelixIntersectPlane(const REveVectorD& p,
838  const REveVectorD& point,
839  const REveVectorD& normal,
840  REveVectorD& itsect)
841 {
842  REveVectorD pos(fV);
843  REveVectorD mom(p);
844  if (fMagFieldObj->IsConst())
845  fH.UpdateHelix(mom, fMagFieldObj->GetFieldD(pos), kFALSE, kFALSE);
846 
847  REveVectorD n(normal);
848  REveVectorD delta = pos - point;
849  Double_t d = delta.Dot(n);
850  if (d > 0) {
851  n.NegateXYZ(); // Turn normal around so that we approach from negative side of the plane
852  d = -d;
853  }
854 
855  REveVector4D forwV;
856  REveVectorD forwP;
857  REveVector4D pos4(pos);
858  while (kTRUE)
859  {
860  Update(pos4, mom);
861  Step(pos4, mom, forwV , forwP);
862  Double_t new_d = (forwV - point).Dot(n);
863  if (new_d < d)
864  {
865  // We are going further away ... fail intersect.
866  Warning("HelixIntersectPlane", "going away from the plane.");
867  return kFALSE;
868  }
869  if (new_d > 0)
870  {
871  delta = forwV - pos;
872  itsect = pos + delta * (d / (d - new_d));
873  return kTRUE;
874  }
875  pos4 = forwV;
876  mom = forwP;
877  }
878 }
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 /// Intersect line with a plane. Current position and argument p define
882 /// the line.
883 
884 Bool_t REveTrackPropagator::LineIntersectPlane(const REveVectorD& p,
885  const REveVectorD& point,
886  const REveVectorD& normal,
887  REveVectorD& itsect)
888 {
889  REveVectorD pos(fV.fX, fV.fY, fV.fZ);
890  REveVectorD delta = point - pos;
891 
892  Double_t pn = p.Dot(normal);
893  if (pn == 0)
894  {
895  return kFALSE;
896  }
897  Double_t t = delta.Dot(normal) / pn;
898  if (t < 0) {
899  return kFALSE;
900  } else {
901  itsect = pos + p*t;
902  return kTRUE;
903  }
904 }
905 
906 ////////////////////////////////////////////////////////////////////////////////
907 /// Find intersection of currently propagated track with a plane.
908 /// Current track position is used as starting point.
909 ///
910 /// Args:
911 /// - p - track momentum to use for extrapolation
912 /// - point - a point on a plane
913 /// - normal - normal of the plane
914 /// - itsect - output, point of intersection
915 /// Returns:
916 /// - kFALSE if intersection can not be found, kTRUE otherwise.
917 
918 Bool_t REveTrackPropagator::IntersectPlane(const REveVectorD& p,
919  const REveVectorD& point,
920  const REveVectorD& normal,
921  REveVectorD& itsect)
922 {
923  if (fH.fCharge && fMagFieldObj && p.Perp2() > kPtMinSqr)
924  return HelixIntersectPlane(p, point, normal, itsect);
925  else
926  return LineIntersectPlane(p, point, normal, itsect);
927 }
928 
929 ////////////////////////////////////////////////////////////////////////////////
930 /// Get closest point from given vertex v to line segment defined with s and r.
931 /// Argument rMagInv is cached. rMagInv= 1./rMag()
932 
933 void REveTrackPropagator::ClosestPointFromVertexToLineSegment(const REveVectorD& v,
934  const REveVectorD& s,
935  const REveVectorD& r,
936  Double_t rMagInv,
937  REveVectorD& c)
938 {
939  REveVectorD dir = v - s;
940  REveVectorD b1 = r * rMagInv;
941 
942  // parallel distance
943  Double_t dot = dir.Dot(b1);
944  REveVectorD dirI = dot * b1;
945 
946  Double_t facX = dot * rMagInv;
947 
948  if (facX <= 0)
949  c = s;
950  else if (facX >= 1)
951  c = s + r;
952  else
953  c = s + dirI;
954 }
955 
956 ////////////////////////////////////////////////////////////////////////////////
957 /// Get closest point on line defined with vector p0 and u.
958 /// Return false if the point is forced on the line segment.
959 
960 Bool_t REveTrackPropagator::ClosestPointBetweenLines(const REveVectorD& p0,
961  const REveVectorD& u,
962  const REveVectorD& q0,
963  const REveVectorD& v,
964  REveVectorD& out)
965 {
966  REveVectorD w0 = p0 -q0;
967  Double_t a = u.Mag2();
968  Double_t b = u.Dot(v);
969  Double_t c = v.Mag2();
970  Double_t d = u.Dot(w0);
971  Double_t e = v.Dot(w0);
972 
973  Double_t x = (b*e - c*d)/(a*c -b*b);
974  Bool_t force = (x < 0 || x > 1);
975  out = p0 + TMath::Range(0., 1., x) * u;
976  return force;
977 }
978 
979 ////////////////////////////////////////////////////////////////////////////////
980 /// Reset ps and populate it with points in propagation cache.
981 
982 void REveTrackPropagator::FillPointSet(REvePointSet* ps) const
983 {
984  Int_t size = TMath::Min(fNMax, (Int_t)fPoints.size());
985  ps->Reset(size);
986  for (Int_t i = 0; i < size; ++i)
987  {
988  const REveVector4D& v = fPoints[i];
989  ps->SetNextPoint(v.fX, v.fY, v.fZ);
990  }
991 }
992 
993 ////////////////////////////////////////////////////////////////////////////////
994 /// Rebuild all tracks using this render-style.
995 
996 void REveTrackPropagator::RebuildTracks()
997 {
998  for (auto &i: fBackRefs) {
999  auto track = dynamic_cast<REveTrack *>(i.first);
1000  if (track) {
1001  track->MakeTrack();
1002  track->StampObjProps();
1003  }
1004  }
1005 }
1006 
1007 ////////////////////////////////////////////////////////////////////////////////
1008 /// Set constant magnetic field and rebuild tracks.
1009 
1010 void REveTrackPropagator::SetMagField(Double_t bX, Double_t bY, Double_t bZ)
1011 {
1012  SetMagFieldObj(new REveMagFieldConst(bX, bY, bZ));
1013 }
1014 
1015 ////////////////////////////////////////////////////////////////////////////////
1016 /// Set constant magnetic field and rebuild tracks.
1017 
1018 void REveTrackPropagator::SetMagFieldObj(REveMagField* field, Bool_t own_field)
1019 {
1020  if (fMagFieldObj && fOwnMagFiledObj) delete fMagFieldObj;
1021 
1022  fMagFieldObj = field;
1023  fOwnMagFiledObj = own_field;
1024 
1025  RebuildTracks();
1026 }
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 
1030 void REveTrackPropagator::PrintMagField(Double_t x, Double_t y, Double_t z) const
1031 {
1032  if (fMagFieldObj) fMagFieldObj->PrintField(x, y, z);
1033 }
1034 
1035 ////////////////////////////////////////////////////////////////////////////////
1036 /// Set maximum radius and rebuild tracks.
1037 
1038 void REveTrackPropagator::SetMaxR(Double_t x)
1039 {
1040  fMaxR = x;
1041  RebuildTracks();
1042 }
1043 
1044 ////////////////////////////////////////////////////////////////////////////////
1045 /// Set maximum z and rebuild tracks.
1046 
1047 void REveTrackPropagator::SetMaxZ(Double_t x)
1048 {
1049  fMaxZ = x;
1050  RebuildTracks();
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Set maximum number of orbits and rebuild tracks.
1055 
1056 void REveTrackPropagator::SetMaxOrbs(Double_t x)
1057 {
1058  fMaxOrbs = x;
1059  RebuildTracks();
1060 }
1061 
1062 ////////////////////////////////////////////////////////////////////////////////
1063 /// Set maximum step angle and rebuild tracks.
1064 /// WARNING -- this method / variable was mis-named.
1065 
1066 void REveTrackPropagator::SetMinAng(Double_t x)
1067 {
1068  Warning("SetMinAng", "This method was mis-named, use SetMaxAng() instead!");
1069  SetMaxAng(x);
1070 }
1071 ////////////////////////////////////////////////////////////////////////////////
1072 /// Get maximum step angle.
1073 /// WARNING -- this method / variable was mis-named.
1074 
1075 Double_t REveTrackPropagator::GetMinAng() const
1076 {
1077  Warning("GetMinAng", "This method was mis-named, use GetMaxAng() instead!");
1078  return GetMaxAng();
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Set maximum step angle and rebuild tracks.
1083 
1084 void REveTrackPropagator::SetMaxAng(Double_t x)
1085 {
1086  fH.fMaxAng = x;
1087  RebuildTracks();
1088 }
1089 
1090 ////////////////////////////////////////////////////////////////////////////////
1091 /// Set maximum step-size and rebuild tracks.
1092 
1093 void REveTrackPropagator::SetMaxStep(Double_t x)
1094 {
1095  fH.fMaxStep = x;
1096  RebuildTracks();
1097 }
1098 
1099 ////////////////////////////////////////////////////////////////////////////////
1100 /// Set maximum error and rebuild tracks.
1101 
1102 void REveTrackPropagator::SetDelta(Double_t x)
1103 {
1104  fH.fDelta = x;
1105  RebuildTracks();
1106 }
1107 
1108 ////////////////////////////////////////////////////////////////////////////////
1109 /// Set daughter creation point fitting and rebuild tracks.
1110 
1111 void REveTrackPropagator::SetFitDaughters(Bool_t x)
1112 {
1113  fFitDaughters = x;
1114  RebuildTracks();
1115 }
1116 
1117 ////////////////////////////////////////////////////////////////////////////////
1118 /// Set track-reference fitting and rebuild tracks.
1119 
1120 void REveTrackPropagator::SetFitReferences(Bool_t x)
1121 {
1122  fFitReferences = x;
1123  RebuildTracks();
1124 }
1125 
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// Set decay fitting and rebuild tracks.
1128 
1129 void REveTrackPropagator::SetFitDecay(Bool_t x)
1130 {
1131  fFitDecay = x;
1132  RebuildTracks();
1133 }
1134 
1135 ////////////////////////////////////////////////////////////////////////////////
1136 /// Set line segment fitting and rebuild tracks.
1137 
1138 void REveTrackPropagator::SetFitLineSegments(Bool_t x)
1139 {
1140  fFitLineSegments = x;
1141  RebuildTracks();
1142 }
1143 
1144 ////////////////////////////////////////////////////////////////////////////////
1145 /// Set 2D-cluster fitting and rebuild tracks.
1146 
1147 void REveTrackPropagator::SetFitCluster2Ds(Bool_t x)
1148 {
1149  fFitCluster2Ds = x;
1150  RebuildTracks();
1151 }
1152 
1153 ////////////////////////////////////////////////////////////////////////////////
1154 /// Set decay rendering and rebuild tracks.
1155 
1156 void REveTrackPropagator::SetRnrDecay(Bool_t rnr)
1157 {
1158  fRnrDecay = rnr;
1159  RebuildTracks();
1160 }
1161 
1162 ////////////////////////////////////////////////////////////////////////////////
1163 /// Set rendering of 2D-clusters and rebuild tracks.
1164 
1165 void REveTrackPropagator::SetRnrCluster2Ds(Bool_t rnr)
1166 {
1167  fRnrCluster2Ds = rnr;
1168  RebuildTracks();
1169 }
1170 
1171 ////////////////////////////////////////////////////////////////////////////////
1172 /// Set daughter rendering and rebuild tracks.
1173 
1174 void REveTrackPropagator::SetRnrDaughters(Bool_t rnr)
1175 {
1176  fRnrDaughters = rnr;
1177  RebuildTracks();
1178 }
1179 
1180 ////////////////////////////////////////////////////////////////////////////////
1181 /// Set track-reference rendering and rebuild tracks.
1182 
1183 void REveTrackPropagator::SetRnrReferences(Bool_t rnr)
1184 {
1185  fRnrReferences = rnr;
1186  RebuildTracks();
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 /// Set first-vertex rendering and rebuild tracks.
1191 
1192 void REveTrackPropagator::SetRnrFV(Bool_t x)
1193 {
1194  fRnrFV = x;
1195  RebuildTracks();
1196 }
1197 
1198 ////////////////////////////////////////////////////////////////////////////////
1199 /// Set projection break-point mode and rebuild tracks.
1200 
1201 void REveTrackPropagator::SetProjTrackBreaking(UChar_t x)
1202 {
1203  fProjTrackBreaking = x;
1204  RebuildTracks();
1205 }
1206 
1207 ////////////////////////////////////////////////////////////////////////////////
1208 /// Set projection break-point rendering and rebuild tracks.
1209 
1210 void REveTrackPropagator::SetRnrPTBMarkers(Bool_t x)
1211 {
1212  fRnrPTBMarkers = x;
1213  RebuildTracks();
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Wrapper to step with method RungeKutta.
1218 
1219 void REveTrackPropagator::StepRungeKutta(Double_t step,
1220  Double_t* vect, Double_t* vout)
1221 {
1222  /// ******************************************************************
1223  /// * *
1224  /// * Runge-Kutta method for tracking a particle through a magnetic *
1225  /// * field. Uses Nystroem algorithm (See Handbook Nat. Bur. of *
1226  /// * Standards, procedure 25.5.20) *
1227  /// * *
1228  /// * Input parameters *
1229  /// * CHARGE Particle charge *
1230  /// * STEP Step size *
1231  /// * VECT Initial co-ords,direction cosines,momentum *
1232  /// * Output parameters *
1233  /// * VOUT Output co-ords,direction cosines,momentum *
1234  /// * User routine called *
1235  /// * CALL GUFLD(X,F) *
1236  /// * *
1237  /// * ==>Called by : <USER>, GUSWIM *
1238  /// * Authors R.Brun, M.Hansroul ********* *
1239  /// * V.Perevoztchikov (CUT STEP implementation) *
1240  /// * *
1241  /// * *
1242  /// ******************************************************************
1243 
1244  Double_t h2, h4, f[4];
1245  Double_t /* xyzt[3], */ a, b, c, ph,ph2;
1246  Double_t secxs[4],secys[4],seczs[4],hxp[3];
1247  Double_t g1, g2, g3, g4, g5, g6, ang2, dxt, dyt, dzt;
1248  Double_t est, at, bt, ct, cba;
1249  Double_t f1, f2, f3, f4, rho, tet, hnorm, hp, rho1, sint, cost;
1250 
1251  Double_t x;
1252  Double_t y;
1253  Double_t z;
1254 
1255  Double_t xt;
1256  Double_t yt;
1257  Double_t zt;
1258 
1259  // const Int_t maxit = 1992;
1260  const Int_t maxit = 500;
1261  const Int_t maxcut = 11;
1262 
1263  const Double_t hmin = 1e-4; // !!! MT ADD, should be member
1264  const Double_t kdlt = 1e-3; // !!! MT CHANGE from 1e-4, should be member
1265  const Double_t kdlt32 = kdlt/32.;
1266  const Double_t kthird = 1./3.;
1267  const Double_t khalf = 0.5;
1268  const Double_t kec = 2.9979251e-3;
1269 
1270  const Double_t kpisqua = 9.86960440109;
1271  const Int_t kix = 0;
1272  const Int_t kiy = 1;
1273  const Int_t kiz = 2;
1274  const Int_t kipx = 3;
1275  const Int_t kipy = 4;
1276  const Int_t kipz = 5;
1277 
1278  // *.
1279  // *. ------------------------------------------------------------------
1280  // *.
1281  // * this constant is for units cm,gev/c and kgauss
1282  // *
1283  Int_t iter = 0;
1284  Int_t ncut = 0;
1285  for(Int_t j = 0; j < 7; j++)
1286  vout[j] = vect[j];
1287 
1288  Double_t pinv = kec * fH.fCharge / vect[6];
1289  Double_t tl = 0.;
1290  Double_t h = step;
1291  Double_t rest;
1292 
1293  do {
1294  rest = step - tl;
1295  if (TMath::Abs(h) > TMath::Abs(rest))
1296  h = rest;
1297 
1298  f[0] = -fH.fB.fX;
1299  f[1] = -fH.fB.fY;
1300  f[2] = -fH.fB.fZ;
1301 
1302  // * start of integration
1303  x = vout[0];
1304  y = vout[1];
1305  z = vout[2];
1306  a = vout[3];
1307  b = vout[4];
1308  c = vout[5];
1309 
1310  h2 = khalf * h;
1311  h4 = khalf * h2;
1312  ph = pinv * h;
1313  ph2 = khalf * ph;
1314  secxs[0] = (b * f[2] - c * f[1]) * ph2;
1315  secys[0] = (c * f[0] - a * f[2]) * ph2;
1316  seczs[0] = (a * f[1] - b * f[0]) * ph2;
1317  ang2 = (secxs[0]*secxs[0] + secys[0]*secys[0] + seczs[0]*seczs[0]);
1318  if (ang2 > kpisqua) break;
1319 
1320  dxt = h2 * a + h4 * secxs[0];
1321  dyt = h2 * b + h4 * secys[0];
1322  dzt = h2 * c + h4 * seczs[0];
1323  xt = x + dxt;
1324  yt = y + dyt;
1325  zt = z + dzt;
1326 
1327  // * second intermediate point
1328  est = TMath::Abs(dxt) + TMath::Abs(dyt) + TMath::Abs(dzt);
1329  if (est > h) {
1330  if (ncut++ > maxcut) break;
1331  h *= khalf;
1332  continue;
1333  }
1334 
1335  // xyzt[0] = xt;
1336  // xyzt[1] = yt;
1337  // xyzt[2] = zt;
1338 
1339  fH.fB = fMagFieldObj->GetFieldD(xt, yt, zt);
1340  f[0] = -fH.fB.fX;
1341  f[1] = -fH.fB.fY;
1342  f[2] = -fH.fB.fZ;
1343 
1344  at = a + secxs[0];
1345  bt = b + secys[0];
1346  ct = c + seczs[0];
1347 
1348  secxs[1] = (bt * f[2] - ct * f[1]) * ph2;
1349  secys[1] = (ct * f[0] - at * f[2]) * ph2;
1350  seczs[1] = (at * f[1] - bt * f[0]) * ph2;
1351  at = a + secxs[1];
1352  bt = b + secys[1];
1353  ct = c + seczs[1];
1354  secxs[2] = (bt * f[2] - ct * f[1]) * ph2;
1355  secys[2] = (ct * f[0] - at * f[2]) * ph2;
1356  seczs[2] = (at * f[1] - bt * f[0]) * ph2;
1357  dxt = h * (a + secxs[2]);
1358  dyt = h * (b + secys[2]);
1359  dzt = h * (c + seczs[2]);
1360  xt = x + dxt;
1361  yt = y + dyt;
1362  zt = z + dzt;
1363  at = a + 2.*secxs[2];
1364  bt = b + 2.*secys[2];
1365  ct = c + 2.*seczs[2];
1366 
1367  est = TMath::Abs(dxt)+TMath::Abs(dyt)+TMath::Abs(dzt);
1368  if (est > 2.*TMath::Abs(h)) {
1369  if (ncut++ > maxcut) break;
1370  h *= khalf;
1371  continue;
1372  }
1373 
1374  // xyzt[0] = xt;
1375  // xyzt[1] = yt;
1376  // xyzt[2] = zt;
1377 
1378  fH.fB = fMagFieldObj->GetFieldD(xt, yt, zt);
1379  f[0] = -fH.fB.fX;
1380  f[1] = -fH.fB.fY;
1381  f[2] = -fH.fB.fZ;
1382 
1383  z = z + (c + (seczs[0] + seczs[1] + seczs[2]) * kthird) * h;
1384  y = y + (b + (secys[0] + secys[1] + secys[2]) * kthird) * h;
1385  x = x + (a + (secxs[0] + secxs[1] + secxs[2]) * kthird) * h;
1386 
1387  secxs[3] = (bt*f[2] - ct*f[1])* ph2;
1388  secys[3] = (ct*f[0] - at*f[2])* ph2;
1389  seczs[3] = (at*f[1] - bt*f[0])* ph2;
1390  a = a+(secxs[0]+secxs[3]+2. * (secxs[1]+secxs[2])) * kthird;
1391  b = b+(secys[0]+secys[3]+2. * (secys[1]+secys[2])) * kthird;
1392  c = c+(seczs[0]+seczs[3]+2. * (seczs[1]+seczs[2])) * kthird;
1393 
1394  est = TMath::Abs(secxs[0]+secxs[3] - (secxs[1]+secxs[2]))
1395  + TMath::Abs(secys[0]+secys[3] - (secys[1]+secys[2]))
1396  + TMath::Abs(seczs[0]+seczs[3] - (seczs[1]+seczs[2]));
1397 
1398  if (est > kdlt && TMath::Abs(h) > hmin) {
1399  if (ncut++ > maxcut) break;
1400  h *= khalf;
1401  continue;
1402  }
1403 
1404  ncut = 0;
1405  // * if too many iterations, go to helix
1406  if (iter++ > maxit) break;
1407 
1408  tl += h;
1409  if (est < kdlt32)
1410  h *= 2.;
1411  cba = 1./ TMath::Sqrt(a*a + b*b + c*c);
1412  vout[0] = x;
1413  vout[1] = y;
1414  vout[2] = z;
1415  vout[3] = cba*a;
1416  vout[4] = cba*b;
1417  vout[5] = cba*c;
1418  rest = step - tl;
1419  if (step < 0.) rest = -rest;
1420  if (rest < 1.e-5*TMath::Abs(step))
1421  {
1422  Float_t dot = (vout[3]*vect[3] + vout[4]*vect[4] + vout[5]*vect[5]);
1423  fH.fPhi += TMath::ACos(dot);
1424  return;
1425  }
1426 
1427  } while(1);
1428 
1429  // angle too big, use helix
1430 
1431  f1 = f[0];
1432  f2 = f[1];
1433  f3 = f[2];
1434  f4 = TMath::Sqrt(f1*f1+f2*f2+f3*f3);
1435  rho = -f4*pinv;
1436  tet = rho * step;
1437 
1438  hnorm = 1./f4;
1439  f1 = f1*hnorm;
1440  f2 = f2*hnorm;
1441  f3 = f3*hnorm;
1442 
1443  hxp[0] = f2*vect[kipz] - f3*vect[kipy];
1444  hxp[1] = f3*vect[kipx] - f1*vect[kipz];
1445  hxp[2] = f1*vect[kipy] - f2*vect[kipx];
1446 
1447  hp = f1*vect[kipx] + f2*vect[kipy] + f3*vect[kipz];
1448 
1449  rho1 = 1./rho;
1450  sint = TMath::Sin(tet);
1451  cost = 2.*TMath::Sin(khalf*tet)*TMath::Sin(khalf*tet);
1452 
1453  g1 = sint*rho1;
1454  g2 = cost*rho1;
1455  g3 = (tet-sint) * hp*rho1;
1456  g4 = -cost;
1457  g5 = sint;
1458  g6 = cost * hp;
1459 
1460  vout[kix] = vect[kix] + g1*vect[kipx] + g2*hxp[0] + g3*f1;
1461  vout[kiy] = vect[kiy] + g1*vect[kipy] + g2*hxp[1] + g3*f2;
1462  vout[kiz] = vect[kiz] + g1*vect[kipz] + g2*hxp[2] + g3*f3;
1463 
1464  vout[kipx] = vect[kipx] + g4*vect[kipx] + g5*hxp[0] + g6*f1;
1465  vout[kipy] = vect[kipy] + g4*vect[kipy] + g5*hxp[1] + g6*f2;
1466  vout[kipz] = vect[kipz] + g4*vect[kipz] + g5*hxp[2] + g6*f3;
1467 
1468  fH.fPhi += tet;
1469 }