From ccee46b404b908389e28d070d1593d376d38318b Mon Sep 17 00:00:00 2001
From: Matevz Tadel <matevz.tadel@cern.ch>
Date: Mon, 12 Jan 2009 19:04:45 +0000
Subject: [PATCH] From Alja.

EveTrackPropagator.cxx, TEveTrackPropagator.h:
Bug fix in track propagation in non-constant magnetic field.
Introduce maximum allowed step size.

tutorials/eve/track.C
Change macro to compare Helix and Runge Kutta stepper for
different types of magnetic field.


git-svn-id: http://root.cern.ch/svn/root/trunk@27119 27541ba8-7e3a-0410-8455-c3a389f83636
---
 graf3d/eve/inc/TEveTrackPropagator.h   |  28 ++--
 graf3d/eve/src/TEveTrackPropagator.cxx | 189 ++++++++++++------------
 tutorials/eve/track.C                  | 194 +++++++++++++++----------
 3 files changed, 218 insertions(+), 193 deletions(-)

diff --git a/graf3d/eve/inc/TEveTrackPropagator.h b/graf3d/eve/inc/TEveTrackPropagator.h
index 626c9633bf7..e0a11bec467 100644
--- a/graf3d/eve/inc/TEveTrackPropagator.h
+++ b/graf3d/eve/inc/TEveTrackPropagator.h
@@ -45,8 +45,6 @@ public:
 
    virtual TEveVector GetField(const TEveVector &v) const { return GetField(v.fX, v.fY, v.fZ);}
    virtual TEveVector GetField(Float_t x, Float_t y, Float_t z) const = 0;
-  
-   virtual Float_t    GetMaxFieldMag() const = 0;
 
    ClassDef(TEveMagField, 0); // Abstract interface to magnetic field
 };
@@ -69,8 +67,6 @@ public:
    using   TEveMagField::GetField;
    virtual TEveVector GetField(Float_t /*x*/, Float_t /*y*/, Float_t /*z*/) const { return fB; }
 
-   virtual Float_t    GetMaxFieldMag() const { return fB.Mag(); }
-
    ClassDef(TEveMagFieldConst, 0); // Interface to constant magnetic field.
 };
 
@@ -87,7 +83,7 @@ protected:
    Float_t    fR2;
 
 public:
-   TEveMagFieldDuo(Float_t r, Float_t bIn, Float_t bOut) : TEveMagField(), 
+   TEveMagFieldDuo(Float_t r, Float_t bIn, Float_t bOut) : TEveMagField(),
      fBIn(0,0,bIn), fBOut(0,0,bOut), fR2(r*r)
    {
       fFieldConstant = kFALSE;
@@ -98,8 +94,6 @@ public:
    virtual TEveVector GetField(Float_t x, Float_t y, Float_t /*z*/) const
    { return  ((x*x+y*y)<fR2) ? fBIn : fBOut; }
 
-   virtual Float_t    GetMaxFieldMag() const { return TMath::Max(fBIn.Mag(), fBOut.Mag()); }
-
    ClassDef(TEveMagFieldDuo, 0); // Interface to magnetic field with two different values depending of radius.
 };
 
@@ -119,6 +113,8 @@ public:
       Int_t   fCharge;   // Charge of tracked particle.
       Float_t fMinAng;   // Minimal angular step between two helix points.
       Float_t fDelta;    // Maximal error at the mid-point of the line connecting two helix points.
+      Float_t fMaxStep;  // Maximum allowed step size.
+      Float_t fCurrentStep;
 
       Float_t fPhi;      // Accumulated angle to check fMaxOrbs by propagator.
       Bool_t  fValid;    // Corner case pT~0 or B~0, possible in variable mag field.
@@ -137,18 +133,18 @@ public:
       TEveVector fPt, fPl;  // Transverse and longitudinal momentum.
       Float_t fPtMag;       // Magnitude of pT
       Float_t fPlDir;       // Momentum parallel to mag field.
-      Float_t fTStep;       // Transverse step arc-length in cm.
+      Float_t fLStep;       // Transverse step arc-length in cm.
 
       // ----------------------------------------------------------------
 
       Helix_t();
 
-      void UpdateHelix(const TEveVector & p, const TEveVector& b, Bool_t fullUpdate, Float_t fraction = -1);
-      void UpdateRG   (const TEveVector & p, const TEveVector& b, Float_t bMax = -1, Float_t maxStep = -1);
+      void UpdateHelix(const TEveVector & p, const TEveVector& b, Bool_t fullUpdate);
+      void UpdateRK   (const TEveVector & p, const TEveVector& b);
       void Step  (const TEveVector4& v, const TEveVector& p, TEveVector4& vOut, TEveVector& pOut);
 
-      Float_t GetStep()  { return fTStep * TMath::Sqrt(1 + fLam*fLam); }
-      Float_t GetStep2() { return fTStep * fTStep * (1 + fLam*fLam);   }
+      Float_t GetStep()  { return fLStep * TMath::Sqrt(1 + fLam*fLam); }
+      Float_t GetStep2() { return fLStep * fLStep * (1 + fLam*fLam);   }
    };
 
    enum EStepper_e    { kHelix, kRungeKutta };
@@ -157,7 +153,7 @@ private:
    TEveTrackPropagator& operator=(const TEveTrackPropagator&); // Not implemented
 
 protected:
-   EStepper_e              fStepper; 
+   EStepper_e               fStepper;
 
    TEveMagField*            fMagFieldObj;
 
@@ -168,8 +164,6 @@ protected:
    // Helix limits
    Float_t                  fMaxOrbs;       // Maximal angular path of tracks' orbits (1 ~ 2Pi).
 
-   Float_t                  fMaxStepRG;     // Maximum step size in stepper RungeKuta.
-
    // Path-mark / first-vertex control
    Bool_t                   fEditPathMarks; // Show widgets for path-mark control in GUI editor.
    Bool_t                   fFitDaughters;  // Pass through daughter creation points when extrapolating a track.
@@ -192,7 +186,7 @@ protected:
    Helix_t                  fH;             // Helix.
 
    void    RebuildTracks();
-   void    Step(TEveVector4 &v, TEveVector &p, TEveVector4 &vOut, TEveVector &pOut, Float_t fraction);
+   void    Step(TEveVector4 &v, TEveVector &p, TEveVector4 &vOut, TEveVector &pOut);
 
    Bool_t  LoopToVertex(TEveVector& v, TEveVector& p);
    void    LoopToBounds(TEveVector& p);
@@ -242,6 +236,7 @@ public:
    void   SetMaxOrbs(Float_t x);
    void   SetMinAng(Float_t x);
    void   SetDelta(Float_t x);
+   void   SetMaxStep(Float_t x);
 
    void   SetEditPathMarks(Bool_t x) { fEditPathMarks = x; }
    void   SetRnrDaughters(Bool_t x);
@@ -264,6 +259,7 @@ public:
    Float_t GetMaxOrbs()  const { return fMaxOrbs;  }
    Float_t GetMinAng()   const { return fH.fMinAng;   }
    Float_t GetDelta()    const { return fH.fDelta;    }
+   Float_t GetMaxStep()  const { return fH.fMaxStep;  }
 
    Bool_t  GetEditPathMarks() const { return fEditPathMarks; }
    Bool_t  GetRnrDaughters()  const { return fRnrDaughters;  }
diff --git a/graf3d/eve/src/TEveTrackPropagator.cxx b/graf3d/eve/src/TEveTrackPropagator.cxx
index 4c30211cf59..ff955637d34 100644
--- a/graf3d/eve/src/TEveTrackPropagator.cxx
+++ b/graf3d/eve/src/TEveTrackPropagator.cxx
@@ -16,19 +16,23 @@
 
 #include <cassert>
 
+static Float_t kBMin = 1e-6;
+static Float_t kPtMinSqr = 1e-5;
+static Float_t kStepEps = 1e-3;
+
 //______________________________________________________________________________
 TEveTrackPropagator::Helix_t::Helix_t() :
    fCharge(0), fMinAng(45), fDelta(0.1),
+   fMaxStep(20.f), fCurrentStep(20.f),
    fPhi(0), fValid(kFALSE),
    fLam(-1), fR(-1), fPhiStep(-1), fSin(-1), fCos(-1),
-   fPtMag(-1), fPlDir(-1), fTStep(-1)
+   fPtMag(-1), fPlDir(-1), fLStep(-1)
 {
    // Default constructor.
 }
 
 //______________________________________________________________________________
-void TEveTrackPropagator::Helix_t::UpdateHelix(const TEveVector& p, const TEveVector& b,
-                                          Bool_t fullUpdate, Float_t fraction)
+void TEveTrackPropagator::Helix_t::UpdateHelix(const TEveVector& p, const TEveVector& b, Bool_t fullUpdate)
 {
    // Update helix parameters.
 
@@ -52,34 +56,33 @@ void TEveTrackPropagator::Helix_t::UpdateHelix(const TEveVector& p, const TEveVe
    if (fullUpdate)
    {
       using namespace TMath;
-
+      fValid = kFALSE;
       Float_t a = fgkB2C * b.Mag() * Abs(fCharge);
-      if (a > 1e-10 && fPtMag*fPtMag > 1e-12)
+      if (a > 1e-10 && fPtMag*fPtMag > kPtMinSqr)
       {
          fValid = kTRUE;
 
          fR   = Abs(fPtMag / a);
          fLam = fPl.Mag() / fPtMag;
          if (fPlDir < 0) fLam = - fLam;
-      }
-      else
-      {
-         fValid = kFALSE;
-         return;
-      }
 
-      // phi steps
-      fPhiStep = fMinAng * DegToRad();
-      if (fDelta < fR)
-      {
-         Float_t ang  = 2*ACos(1 - fDelta/fR);
-         if (ang < fPhiStep) fPhiStep = ang;
-      }
-      if (fraction > 0) fPhiStep *= fraction;
+         // get phi step, compare fMinAng with fDelta
+         fPhiStep = fMinAng * DegToRad();
+         if (fDelta < fR)
+         {
+            Float_t ang  = 2*ACos(1 - fDelta/fR);
+            if (ang < fPhiStep) fPhiStep = ang;
+         }
+
+         // check max step size
+         fCurrentStep = fR*fPhiStep*(1 + fLam*fLam);
+         if (fCurrentStep > fMaxStep)
+            fPhiStep *= (fMaxStep/fCurrentStep);
 
-      fTStep = fR*fPhiStep;
-      fSin   = Sin(fPhiStep);
-      fCos   = Cos(fPhiStep);
+         fLStep = fR*fPhiStep*fLam;
+         fSin   = Sin(fPhiStep);
+         fCos   = Cos(fPhiStep);
+      }
    }
 }
 
@@ -93,9 +96,9 @@ void TEveTrackPropagator::Helix_t::Step(const TEveVector4& v, const TEveVector&
 
    if (fValid)
    {
-      TEveVector d = fE2*(fR*fSin) + fE3*(fR*(1-fCos)) + fE1*(fLam*fTStep);
+      TEveVector d = fE2*(fR*fSin) + fE3*(fR*(1-fCos)) + fE1*fLStep;
       vOut    += d;
-      vOut.fT += fTStep;
+      vOut.fT += fLStep;
 
       pOut = fPl + fE2*(fPtMag*fCos) + fE3*(fPtMag*fSin);
 
@@ -103,44 +106,31 @@ void TEveTrackPropagator::Helix_t::Step(const TEveVector4& v, const TEveVector&
    }
    else
    {
-      // case: pT < 1e-6 or B < 1e-7
+      // case: pT < kPtMinSqr or B < kBMin
       // might happen if field directon changes pT ~ 0 or B becomes zero
-
-      if (fTStep == -1)
-      {
-         printf("WARNING TEveTrackPropagator::Helix_t::Step step-size not initialised.\n");
-      }
-      vOut += p * (fTStep / p.Mag());
+      vOut += p * (fMaxStep / p.Mag());
       pOut  = p;
    }
 }
 
 
 //______________________________________________________________________________
-void TEveTrackPropagator::Helix_t::UpdateRG(const TEveVector& p,  const TEveVector& b, Float_t bMax, Float_t maxStep)
+void TEveTrackPropagator::Helix_t::UpdateRK(const TEveVector& p, const TEveVector& b)
 {
-  // Update helix for stepper RungeKutta.
-
-  if (bMax > 0)
-  {
-    // full update
-    Float_t a  = fgkB2C * bMax * fCharge;
-    fPhiStep = fMinAng * TMath::DegToRad();
-    if (a)
-    {
-      fR      = TMath::Abs(p.Mag() / a);
-      fTStep   = TMath::Min(fR*fPhiStep, maxStep);
+   // Update helix for stepper RungeKutta.
+
+   if (TMath::Abs(b.Mag()) > kBMin && fCharge)
+   {
       fValid = kTRUE;
-    }
-    else 
-    {
-      fValid = kFALSE;
-      fTStep = maxStep;
-    }
-  }
 
-  fB = b;
-  fPlDir = p.Dot(fB);
+      // cached values for propagator
+      fB = b;
+      fPlDir = p.Dot(fB);
+   }
+   else
+   {
+      fValid = kFALSE;
+   }
 }
 
 
@@ -179,7 +169,6 @@ TEveTrackPropagator::TEveTrackPropagator(const Text_t* n, const Text_t* t,
 
    fNMax     (4096),
    fMaxOrbs  (0.5),
-   fMaxStepRG  (10),
 
    fEditPathMarks (kTRUE),
    fFitDaughters  (kTRUE),
@@ -295,10 +284,9 @@ Bool_t TEveTrackPropagator::GoToVertex(TEveVector& v, TEveVector& p)
    if (fStepper == kHelix)
       fH.UpdateHelix(p, fMagFieldObj->GetField(fV), kTRUE);
    else
-      fH.UpdateRG(p, fMagFieldObj->GetField(fV), fMagFieldObj->GetMaxFieldMag(), fMaxStepRG);
+      fH.UpdateRK(p, fMagFieldObj->GetField(fV));
 
-
-   if ((v-fV).Mag() < 1e-3)
+   if ((v-fV).Mag() < kStepEps)
    {
       fPoints.push_back(v);
       return kTRUE;
@@ -312,55 +300,50 @@ void TEveTrackPropagator::GoToBounds(TEveVector& p)
 {
    // Propagate particle to bounds.
    // Return TRUE if hit bounds.
-  
+
    if (fStepper == kHelix)
       fH.UpdateHelix(p, fMagFieldObj->GetField(fV), kTRUE);
    else
-      fH.UpdateRG(p, fMagFieldObj->GetField(fV), fMagFieldObj->GetMaxFieldMag(), fMaxStepRG);
+      fH.UpdateRK(p, fMagFieldObj->GetField(fV));
 
-    
    fH.fValid ? LoopToBounds(p): LineToBounds(p);
 }
 
 //______________________________________________________________________________
-void TEveTrackPropagator::Step(TEveVector4 &v, TEveVector &p, TEveVector4 &vOut, TEveVector &pOut,
-                               Float_t fraction = -1)
+void TEveTrackPropagator::Step(TEveVector4 &v, TEveVector &p, TEveVector4 &vOut, TEveVector &pOut)
 {
    // Wrapper to step helix.
 
    if (fStepper == kHelix)
    {
-      fH.UpdateHelix(p, fH.fB, !fMagFieldObj->IsConst(), fraction);
+      fH.UpdateHelix(p, fMagFieldObj->GetField(v), !fMagFieldObj->IsConst());
       fH.Step(v, p, vOut, pOut);
    }
    else
    {
-      fH.UpdateRG(p, fMagFieldObj->GetField(fV));
-      Float_t step = fH.fTStep;
-      if (fraction > 0)
-         step *= fraction;
-
-      Double_t vecRGI[7];
-      vecRGI[0] = v.fX;
-      vecRGI[1] = v.fY;
-      vecRGI[2] = v.fZ;
+      fH.UpdateRK(p, fMagFieldObj->GetField(v));
+
+      Double_t vecRKIn[7];
+      vecRKIn[0] = v.fX;
+      vecRKIn[1] = v.fY;
+      vecRKIn[2] = v.fZ;
       Float_t nm = 1/p.Mag();
-      vecRGI[3] = p.fX*nm;
-      vecRGI[4] = p.fY*nm;
-      vecRGI[5] = p.fZ*nm;
-      vecRGI[6] = p.Mag();
-
-      Double_t vecRGO[7];
-      OneStepRungeKutta(fH.fCharge, step, vecRGI, vecRGO);
-
-      vOut.fX = vecRGO[0];
-      vOut.fY = vecRGO[1];
-      vOut.fZ = vecRGO[2];
-      vOut.fT += step;
-      Double_t pm = vecRGO[6];
-      pOut.fX = vecRGO[3]*pm;
-      pOut.fY = vecRGO[4]*pm;
-      pOut.fZ = vecRGO[5]*pm;
+      vecRKIn[3] = p.fX*nm;
+      vecRKIn[4] = p.fY*nm;
+      vecRKIn[5] = p.fZ*nm;
+      vecRKIn[6] = p.Mag();
+
+      Double_t vecRKOut[7];
+      OneStepRungeKutta(fH.fCharge, fH.fMaxStep, vecRKIn, vecRKOut);
+
+      vOut.fX = vecRKOut[0];
+      vOut.fY = vecRKOut[1];
+      vOut.fZ = vecRKOut[2];
+      vOut.fT += fH.fMaxStep;
+      Double_t pm = vecRKOut[6];
+      pOut.fX = vecRKOut[3]*pm;
+      pOut.fY = vecRKOut[4]*pm;
+      pOut.fZ = vecRKOut[5]*pm;
    }
 }
 
@@ -468,22 +451,23 @@ Bool_t TEveTrackPropagator::LoopToVertex(TEveVector& v, TEveVector& p)
       TEveVector pln =  fH.fPl;
       pln.Normalize();
 
-      if (pln.Dot(d2) > 1e-10)
+      if (d1.Mag() > kStepEps)
       {
-         // set step fraction
-         Float_t frac = pln.Dot(d1)/pln.Dot(d2);
-         //  printf("frac %f %d p (%f %f %f)\n", frac, np-first_point, fH.fPl.fX, fH.fPl.fY, fH.fPl.fZ);
-
+         // step for forced step size;
+         Float_t origMaxStep = fH.fMaxStep;
+         fH.fMaxStep = d1.Mag();
          if (fStepper == kHelix)
-            fH.UpdateHelix(p, fH.fB, kTRUE, frac);
+            fH.UpdateHelix(p, fMagFieldObj->GetField(fV), kTRUE);
          else
-            fH.fTStep *= frac; 
+            fH.UpdateRK(p, fMagFieldObj->GetField(fV));
 
          Step(currV, p, forwV, forwP);
          p = forwP;
          currV = forwV;
          fPoints.push_back(currV); np++;
+         fH.fMaxStep =  origMaxStep;
 
+         // distibute offset
          TEveVector off(v); off -= currV;
          off *= 1.0f / currV.fT;
          for (Int_t i = first_point; i < np; ++i)
@@ -561,7 +545,7 @@ Bool_t TEveTrackPropagator::HelixIntersectPlane(const TEveVector& p,
    TEveVector pos(fV);
    TEveVector mom(p);
    if (fMagFieldObj->IsConst())
-      fH.UpdateHelix(mom, fMagFieldObj->GetField(pos), fH.fCharge,  kTRUE);
+      fH.UpdateHelix(mom, fMagFieldObj->GetField(pos), kFALSE);
 
    TEveVector n(normal);
    TEveVector delta = pos - point;
@@ -636,7 +620,7 @@ Bool_t TEveTrackPropagator::IntersectPlane(const TEveVector& p,
    // Returns:
    //  kFALSE if intersection can not be found, kTRUE otherwise.
 
-   if (fH.fCharge && fMagFieldObj && p.Perp2() > 1e-12)
+   if (fH.fCharge && fMagFieldObj && p.Perp2() > kPtMinSqr)
       return HelixIntersectPlane(p, point, normal, itsect);
    else
       return LineIntersectPlane(p, point, normal, itsect);
@@ -818,6 +802,14 @@ void TEveTrackPropagator::SetRnrReferences(Bool_t rnr)
    RebuildTracks();
 }
 
+//______________________________________________________________________________
+void TEveTrackPropagator::SetMaxStep(Float_t x)
+{
+   // Set maximum radius and rebuild tracks.
+
+   fH.fMaxStep = x;
+   RebuildTracks();
+}
 
 //______________________________________________________________________________
 void TEveTrackPropagator::OneStepRungeKutta(Double_t charge, Double_t step,
@@ -897,7 +889,6 @@ void TEveTrackPropagator::OneStepRungeKutta(Double_t charge, Double_t step,
   Double_t h = step;
   Double_t rest;
 
-
   do {
     rest  = step - tl;
     if (TMath::Abs(h) > TMath::Abs(rest)) h = rest;
@@ -950,6 +941,7 @@ void TEveTrackPropagator::OneStepRungeKutta(Double_t charge, Double_t step,
     xyzt[2] = zt;
 
     //cmodif: call gufld(xyzt,f) changed into:
+    fH.fB = fMagFieldObj->GetField(xt, yt, zt);
     f[0] = -fH.fB.fX;
     f[1] = -fH.fB.fY;
     f[2] = -fH.fB.fZ;
@@ -989,6 +981,7 @@ void TEveTrackPropagator::OneStepRungeKutta(Double_t charge, Double_t step,
     xyzt[2] = zt;
 
     //cmodif: call gufld(xyzt,f) changed into:
+    fH.fB = fMagFieldObj->GetField(xt, yt, zt);
     f[0] = -fH.fB.fX;
     f[1] = -fH.fB.fY;
     f[2] = -fH.fB.fZ;
@@ -1074,7 +1067,7 @@ void TEveTrackPropagator::OneStepRungeKutta(Double_t charge, Double_t step,
 
   vout[kipx] = vect[kipx] + g4*vect[kipx] + g5*hxp[0] + g6*f1;
   vout[kipy] = vect[kipy] + g4*vect[kipy] + g5*hxp[1] + g6*f2;
-  vout[kipz] = vect[kipz] + g4*vect[kipz] + g5*hxp[2] + g6*f3; 
+  vout[kipz] = vect[kipz] + g4*vect[kipz] + g5*hxp[2] + g6*f3;
 
   fH.fPhi += tet;
 }
diff --git a/tutorials/eve/track.C b/tutorials/eve/track.C
index 7859e86fb4a..251e798a5e8 100644
--- a/tutorials/eve/track.C
+++ b/tutorials/eve/track.C
@@ -3,55 +3,31 @@
 
 // Makes some tracks with three different magnetic field types.
 
-void track(Int_t bCase = 2)
+#include "TEveTrackPropagator.h"
+#include "TEveTrack.h"
+#include "TEveManager.h"
+#include "TEveViewer.h"
+#include "TSystem.h"
+#include "TGLViewer.h"
+#include "TMath.h"
+
+#include "TEveViewer.h"
+#include "TEvePointSet.h"
+
+class GappedField : public TEveMagField
 {
-  gSystem->IgnoreSignal(kSigSegmentationViolation, true);
-  TEveManager::Create();
-
-  TEveTrackPropagator* prop = new TEveTrackPropagator();
-  prop->SetRnrDaughters(kTRUE);
-  gEve->AddElement(prop);
-
-  TEveTrack *track = 0;
-  switch (bCase)
-  {
-    case 0:
-    {
-      // B = 0 no difference btween signed and charge particles
-      prop->SetMagField(0.);
-      prop->SetName("ZeroB");
-      track = make_track(prop, 0);
-      track = make_track(prop, 1);
-      break;
-    }
-
-    case 1:
-    {
-      // constant B field, const angle
-      prop->SetMagFieldObj(new TEveMagFieldConst(0., 0., -3.8));
-      prop->SetName("ConstB");
-      prop->SetMaxR(123);
-      prop->SetMaxZ(300);
-      track = make_track(prop, 0);
-      track = make_track(prop, -1);
-      break;
-    }
-    case 2:
-    {
-      // variable B field, sign change at  R = 200 cm
-      prop->SetMagFieldObj(new TEveMagFieldDuo(200, -4.4, 2));
-      prop->SetName("DuoB");
-      prop->SetMaxR(600);
-      prop->SetMaxZ(700);
-      prop->SetMinAng(1.f);
-      track = make_track(prop, 0);
-      track = make_track(prop, -1);
-      break;
-    }
-  };
-  //  make_projected(track);
-  gEve->Redraw3D(1);
-}
+public:
+   GappedField():TEveMagField(){}
+   ~GappedField(){};
+   using   TEveMagField::GetField;
+
+   virtual TEveVector GetField(Float_t /*x*/, Float_t /*y*/, Float_t z) const
+   {
+      if (TMath::Abs(z) < 300) return TEveVector(0, 0, -4);
+      if (TMath::Abs(z) < 600) return TEveVector(0, 0, 0);
+      return TEveVector(0, 0, 4);
+   }
+};
 
 //______________________________________________________________________________
 TEveTrack* make_track(TEveTrackPropagator* prop, Int_t sign)
@@ -63,9 +39,10 @@ TEveTrack* make_track(TEveTrackPropagator* prop, Int_t sign)
   rc->fV.Set(0.028558, -0.000918, 3.691919);
   rc->fP.Set(0.767095, -2.400006, -0.313103);
   rc->fSign = sign;
+
+
   TEveTrack* track = new TEveTrack(rc, prop);
   track->SetName(Form("Charge %d", sign));
-
   // daughter 0
   TEvePathMark* pm1 = new TEvePathMark(TEvePathMark::kDaughter);
   pm1->fV.Set(1.479084, -4.370661, 3.119761);
@@ -75,38 +52,97 @@ TEveTrack* make_track(TEveTrackPropagator* prop, Int_t sign)
   pm2->fV.Set(57.72345, -89.77011, -9.783746);
   track->AddPathMark(*pm2);
 
-  // color by sign
-  if (sign)
-  {
-    track->SetLineColor(kRed-3);
-    track->SetLineWidth(2);
-  }
-  else
-  {
-    track->SetLineColor(kOrange);
-  }
-
-  track->MakeTrack();
-  gEve->AddElement(track, prop);
-
   return track;
 }
 
-//______________________________________________________________________________
-void make_projected(TEveTrack *track)
+
+void track(Int_t bCase = 3, Bool_t isRungeKutta = kTRUE)
 {
-   // Make non-linear projected view.
-
-  TEveViewer* v1 = gEve->SpawnNewViewer("2D Viewer");
-  TEveScene*  s1 = gEve->SpawnNewScene("Projected Event");
-  v1->AddScene(s1);
-  TGLViewer* v = v1->GetGLViewer();
-  v->SetCurrentCamera(TGLViewer::kCameraOrthoXOY);
-  v->SetGuideState(TGLUtil::kAxesOrigin, kTRUE, kFALSE, 0);
-
-  TEveProjectionManager* mng = new TEveProjectionManager();
-  mng->SetProjection(TEveProjection::kPT_RhoZ);
-  gEve->AddElement(mng, s1);
-  gEve->AddToListTree(mng, kTRUE);
-  mng->ImportElements(track);
+#if defined (__CINT__)
+   Error("track.C", "Must be run in compiled mode!");
+   return;
+#endif
+
+   gSystem->IgnoreSignal(kSigSegmentationViolation, true);
+   TEveManager::Create();
+
+   TEveTrackList *list = new TEveTrackList();
+   TEveTrackPropagator* prop = list->GetPropagator();
+   prop->SetFitDaughters(kFALSE);
+   prop->SetMaxZ(1000);
+
+   if (isRungeKutta)
+   {
+      prop->SetStepper(TEveTrackPropagator::kRungeKutta);
+      list->SetName("RK Propagator");
+   }
+   else
+   {
+      list->SetName("Heix Propagator");
+   }
+
+   TEveTrack *track = 0;
+   switch (bCase)
+   {
+      case 0:
+      {
+         // B = 0 no difference btween signed and charge particles
+         prop->SetMagField(0.);
+         list->SetElementName(Form("%s, zeroB", list->GetElementName()));
+         track = make_track(prop, 1);
+         break;
+      }
+
+      case 1:
+      {
+         // constant B field, const angle
+         prop->SetMagFieldObj(new TEveMagFieldConst(0., 0., -3.8));
+         list->SetElementName(Form("%s, constB", list->GetElementName()));
+         track = make_track(prop, 1);
+         break;
+      }
+      case 2:
+      {
+         // variable B field, sign change at  R = 200 cm
+         prop->SetMagFieldObj(new TEveMagFieldDuo(200, -4.4, 2));
+         list->SetElementName(Form("%s, duoB", list->GetElementName()));
+         track = make_track(prop, 1);
+         break;
+      }
+      case 3:
+      {
+         // gapped field
+         prop->SetMagFieldObj(new GappedField());
+         list->SetElementName(Form("%s, gappedB", list->GetElementName()));
+
+      
+         TEveRecTrack *rc = new TEveRecTrack();
+         rc->fV.Set(0.028558, -0.000918, 3.691919);
+         rc->fP.Set(0.767095, -0.400006, 2.313103);
+         rc->fSign = 1;
+         track = new TEveTrack(rc, prop);
+
+         TEvePointSet* marker = new TEvePointSet(2);  
+         marker->SetElementName("B field break points");
+         marker->SetPoint(0, 0., 0., 300.f);
+         marker->SetPoint(1, 0., 0., 600.f);
+         marker->SetMarkerColor(3);
+         gEve->AddElement(marker);
+      }
+   };
+       
+   if (isRungeKutta)
+      list->SetLineColor(kMagenta);
+   else 
+      list->SetLineColor(kCyan);
+
+   track->SetLineColor(list->GetLineColor());
+ 
+   gEve->AddElement(track, list);
+   gEve->AddElement(list);
+   track->MakeTrack();
+
+   TEveViewer* v = gEve->GetDefaultViewer();
+   v->GetGLViewer()->SetGuideState(TGLUtil::kAxesOrigin, kTRUE, kFALSE, 0);
+   gEve->Redraw3D(1);
 }
-- 
GitLab