TGeoHelix.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoHelix.cxx 34999 2010-08-25 11:16:02Z agheata $
00002 // Author: Andrei Gheata   28/04/04
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 
00013 ////////////////////////////////////////////////////////////////////////////////
00014 //   TGeoHelix - class representing a helix curve
00015 //
00016 //  A helix is a curve defined by the following equations:
00017 //     x = (1/c) * COS(q*phi)
00018 //     y = (1/c) * SIN(q*phi)
00019 //     z = s * alfa
00020 // where:
00021 //     c = 1/Rxy  - curvature in XY plane
00022 //     phi        - phi angle 
00023 //     S = 2*PI*s - vertical separation between helix loops
00024 //     q = +/- 1  - (+)=left-handed, (-)=right-handed
00025 //
00026 //   In particular, a helix describes the trajectory of a charged particle in magnetic 
00027 // field. In such case, the helix is right-handed for negative particle charge.
00028 // To define a helix, one must define:
00029 //   - the curvature - positive defined
00030 //   - the Z step made after one full turn of the helix
00031 //   - the particle charge sign
00032 //   - the initial particle position and direction (force normalization to unit)
00033 //   - the magnetic field direction
00034 //
00035 // A helix provides:
00036 //   - propagation to a given Z position (in global frame)
00037 //   Double_t *point = TGeoHelix::PropagateToZ(Double_t z);
00038 //   - propagation to an arbitrary plane, returning also the new point
00039 //   - propagation in a geometry until the next crossed surface
00040 //   - computation of the total track length along a helix
00041 
00042 #include "TMath.h"
00043 #include "TGeoShape.h"
00044 #include "TGeoMatrix.h"
00045 #include "TGeoHelix.h"
00046 
00047 ClassImp(TGeoHelix)
00048 
00049 //_____________________________________________________________________________
00050 TGeoHelix::TGeoHelix()
00051 { 
00052 // Dummy constructor
00053    fC    = 0.;
00054    fS    = 0.;
00055    fStep = 0.;
00056    fPhi  = 0.;
00057    fPointInit[0] = fPointInit[1] = fPointInit[2] = 0.;
00058    fDirInit[0] = fDirInit[1] = fDirInit[2] = 0.;
00059    fPoint[0] = fPoint[1] = fPoint[2] = 0.;
00060    fDir[0] = fDir[1] = fDir[2] = 0.;
00061    fB[0] = fB[1] = fB[2] = 0.;
00062    fQ    = 0;
00063    fMatrix = 0;
00064    TObject::SetBit(kHelixNeedUpdate, kTRUE);   
00065    TObject::SetBit(kHelixStraigth, kFALSE);
00066    TObject::SetBit(kHelixCircle, kFALSE);
00067 }
00068 
00069 //_____________________________________________________________________________
00070 TGeoHelix::TGeoHelix(Double_t curvature, Double_t hstep, Int_t charge)
00071 { 
00072 // Normal constructor
00073    SetXYcurvature(curvature);
00074    SetHelixStep(hstep);
00075    SetCharge(charge);
00076    fStep = 0.;
00077    fPhi  = 0.;
00078    fPointInit[0] = fPointInit[1] = fPointInit[2] = 0.;
00079    fDirInit[0] = fDirInit[1] = fDirInit[2] = 0.;
00080    fPoint[0] = fPoint[1] = fPoint[2] = 0.;
00081    fDir[0] = fDir[1] = fDir[2] = 0.;
00082    fB[0] = fB[1] = fB[2] = 0.;
00083    fQ    = 0;
00084    fMatrix    = new TGeoHMatrix();
00085    TObject::SetBit(kHelixNeedUpdate, kTRUE);   
00086    TObject::SetBit(kHelixStraigth, kFALSE);
00087    TObject::SetBit(kHelixCircle, kFALSE);
00088 }
00089 
00090 //_____________________________________________________________________________
00091 TGeoHelix::~TGeoHelix()
00092 {
00093 // Destructor
00094    if (fMatrix)    delete fMatrix;
00095 }
00096 
00097 //_____________________________________________________________________________
00098 Double_t TGeoHelix::ComputeSafeStep(Double_t epsil) const
00099 {
00100 // Compute safe linear step that can be made such that the error
00101 // between linear-helix extrapolation is less than EPSIL.
00102    if (TestBit(kHelixStraigth) || TMath::Abs(fC)<TGeoShape::Tolerance()) return 1.E30;
00103    Double_t c = GetTotalCurvature();
00104    Double_t step = TMath::Sqrt(2.*epsil/c);
00105    return step;
00106 }   
00107 
00108 //_____________________________________________________________________________
00109 void TGeoHelix::InitPoint(Double_t x0, Double_t y0, Double_t z0)
00110 {
00111 // Initialize coordinates of a point on the helix
00112    fPointInit[0] = x0;
00113    fPointInit[1] = y0;
00114    fPointInit[2] = z0;
00115    TObject::SetBit(kHelixNeedUpdate, kTRUE);   
00116 }   
00117 
00118 //_____________________________________________________________________________
00119 void TGeoHelix::InitPoint (Double_t *point)
00120 {
00121 // Set initial point on the helix.
00122    InitPoint(point[0], point[1], point[2]);
00123 }
00124 
00125 //_____________________________________________________________________________
00126 void TGeoHelix::InitDirection(Double_t dirx, Double_t diry, Double_t dirz, Bool_t is_normalized)
00127 {
00128 // Initialize particle direction (tangent on the helix in initial point)   
00129    fDirInit[0] = dirx;
00130    fDirInit[1] = diry;
00131    fDirInit[2] = dirz;
00132    TObject::SetBit(kHelixNeedUpdate, kTRUE);
00133    if (is_normalized) return;
00134    Double_t norm = 1./TMath::Sqrt(dirx*dirx+diry*diry+dirz*dirz);
00135    for (Int_t i=0; i<3; i++) fDirInit[i] *= norm;   
00136 }   
00137    
00138 //_____________________________________________________________________________
00139 void TGeoHelix::InitDirection(Double_t *dir, Bool_t is_normalized)
00140 {
00141 // Initialize particle direction (tangent on the helix in initial point)   
00142    InitDirection(dir[0], dir[1], dir[2], is_normalized);
00143 }     
00144 
00145 //_____________________________________________________________________________
00146 Double_t TGeoHelix::GetTotalCurvature() const
00147 {
00148 // Compute helix total curvature
00149    Double_t k = fC/(1.+fC*fC*fS*fS);
00150    return k;
00151 }
00152 
00153 //_____________________________________________________________________________
00154 void TGeoHelix::SetXYcurvature(Double_t curvature)
00155 {
00156 // Set XY curvature: c = 1/Rxy
00157    fC    = curvature;
00158    TObject::SetBit(kHelixNeedUpdate, kTRUE);
00159    if (fC < 0) {
00160       Error("SetXYcurvature", "Curvature %f not valid. Must be positive.", fC);
00161       return;
00162    } 
00163    if (TMath::Abs(fC) < TGeoShape::Tolerance()) {
00164       Warning("SetXYcurvature", "Curvature is zero. Helix is a straigth line.");      
00165       TObject::SetBit(kHelixStraigth, kTRUE);
00166    }   
00167 }  
00168 
00169 //_____________________________________________________________________________
00170 void TGeoHelix::SetCharge(Int_t charge)
00171 {
00172 // Positive charge means left-handed helix.   
00173    if (charge==0) {
00174       Error("ctor", "charge cannot be 0 - define it positive for a left-handed helix, negative otherwise");
00175       return;
00176    }   
00177    Int_t q = TMath::Sign(1, charge);
00178    if (q == fQ) return;
00179    fQ = q;
00180    TObject::SetBit(kHelixNeedUpdate, kTRUE);
00181 }   
00182 
00183 //_____________________________________________________________________________
00184 void TGeoHelix::SetField(Double_t bx, Double_t by, Double_t bz, Bool_t is_normalized)
00185 {
00186 // Initialize particle direction (tangent on the helix in initial point)   
00187    fB[0] = bx;
00188    fB[1] = by;
00189    fB[2] = bz;
00190    TObject::SetBit(kHelixNeedUpdate, kTRUE);
00191    if (is_normalized) return;
00192    Double_t norm = 1./TMath::Sqrt(bx*bx+by*by+bz*bz);
00193    for (Int_t i=0; i<3; i++) fB[i] *= norm;   
00194 }
00195 
00196 //_____________________________________________________________________________
00197 void TGeoHelix::SetHelixStep(Double_t step)
00198 {
00199 // Set Z step of the helix on a complete turn. Positive or null.
00200    if (step < 0) {
00201       Error("ctor", "Z step %f not valid. Must be positive.", step);
00202       return;
00203    }   
00204    TObject::SetBit(kHelixNeedUpdate, kTRUE);
00205    fS    = 0.5*step/TMath::Pi();
00206    if (fS < TGeoShape::Tolerance()) TObject::SetBit(kHelixCircle, kTRUE);
00207 }   
00208 
00209 //_____________________________________________________________________________
00210 void TGeoHelix::ResetStep()
00211 {
00212 // Reset current point/direction to initial values
00213    fStep = 0.;
00214    memcpy(fPoint, fPointInit, 3*sizeof(Double_t));
00215    memcpy(fDir, fDirInit, 3*sizeof(Double_t));
00216 }   
00217 
00218 //_____________________________________________________________________________
00219 void TGeoHelix::Step(Double_t step)
00220 {
00221 // Make a step from current point along the helix and compute new point, direction and angle
00222 // To reach a plane/ shape boundary, one has to:
00223 //  1. Compute the safety to the plane/boundary
00224 //  2. Define / update a helix according local field and particle state (position, direction, charge)
00225 //  3. Compute the magnetic safety (maximum distance for which the field can be considered constant)
00226 //  4. Call TGeoHelix::Step() having as argument the minimum between 1. and 3.
00227 //  5. Repeat from 1. until the step to be made is small enough.
00228 //  6. Add to the total step the distance along a straigth line from the last point
00229 //     to the plane/shape boundary
00230    Int_t i;
00231    fStep += step;
00232    if (TObject::TestBit(kHelixStraigth)) {
00233       for (i=0; i<3; i++) {
00234          fPoint[i] = fPointInit[i]+fStep*fDirInit[i];
00235          fDir[i] = fDirInit[i];
00236       }   
00237       return;
00238    }
00239    if (TObject::TestBit(kHelixNeedUpdate)) UpdateHelix();
00240    Double_t r = 1./fC;
00241    fPhi = fStep/TMath::Sqrt(r*r+fS*fS);
00242    Double_t vect[3];
00243    vect[0] = r * TMath::Cos(fPhi);  
00244    vect[1] = -fQ * r * TMath::Sin(fPhi);  
00245    vect[2] = fS * fPhi;
00246    fMatrix->LocalToMaster(vect, fPoint);
00247 
00248    Double_t ddb = fDirInit[0]*fB[0]+fDirInit[1]*fB[1]+fDirInit[2]*fB[2];
00249    Double_t f = -TMath::Sqrt(1.-ddb*ddb);
00250    vect[0] = f*TMath::Sin(fPhi);
00251    vect[1] = fQ*f*TMath::Cos(fPhi);
00252    vect[2] = ddb;
00253    fMatrix->LocalToMasterVect(vect, fDir);   
00254 }
00255 
00256 //_____________________________________________________________________________
00257 Double_t TGeoHelix::StepToPlane(Double_t *point, Double_t *norm) 
00258 {
00259 // Propagate initial point up to a given Z position in MARS.
00260    Double_t step = 0.;
00261    Double_t snext = 1.E30;
00262    Double_t dx, dy, dz;
00263    Double_t ddn, pdn;
00264    if (TObject::TestBit(kHelixNeedUpdate)) UpdateHelix();
00265    dx = point[0] - fPoint[0];
00266    dy = point[1] - fPoint[1];
00267    dz = point[2] - fPoint[2];
00268    pdn = dx*norm[0]+dy*norm[1]+dz*norm[2];
00269    ddn = fDir[0]*norm[0]+fDir[1]*norm[1]+fDir[2]*norm[2];
00270    if (TObject::TestBit(kHelixStraigth)) {
00271       // propagate straigth line to plane
00272       if ((pdn*ddn) <= 0) return snext;
00273       snext = pdn/ddn;
00274       Step(snext);
00275       return snext;
00276    }   
00277    
00278    Double_t r = 1./fC;
00279    Double_t dist;
00280    Double_t safety = TMath::Abs(pdn);
00281    Double_t safestep = ComputeSafeStep();
00282    snext = 1.E30;
00283    Bool_t approaching = (ddn*pdn>0)?kTRUE:kFALSE;
00284    if (approaching) snext = pdn/ddn;
00285    else if (safety > 2.*r) return snext;
00286    while (snext > safestep) {
00287       dist = TMath::Max(safety, safestep);
00288       Step(dist);
00289       step += dist;
00290       dx = point[0] - fPoint[0];
00291       dy = point[1] - fPoint[1];
00292       dz = point[2] - fPoint[2];
00293       pdn = dx*norm[0]+dy*norm[1]+dz*norm[2];
00294       ddn = fDir[0]*norm[0]+fDir[1]*norm[1]+fDir[2]*norm[2];
00295       safety = TMath::Abs(pdn);
00296       approaching = (ddn*pdn>0)?kTRUE:kFALSE;
00297       snext = 1.E30;
00298       if (approaching) snext = pdn/ddn;
00299       else if (safety > 2.*r) {
00300          ResetStep();
00301          return snext; 
00302       }   
00303    }
00304    step += snext;
00305    Step(snext);
00306    return step;
00307 }
00308 
00309 //_____________________________________________________________________________
00310 void TGeoHelix::UpdateHelix()
00311 {
00312 // Update the local helix matrix.
00313    TObject::SetBit(kHelixNeedUpdate, kFALSE);
00314    fStep = 0.;
00315    memcpy(fPoint, fPointInit, 3*sizeof(Double_t));
00316    memcpy(fDir, fDirInit, 3*sizeof(Double_t));
00317    Double_t rot[9];
00318    Double_t tr[3];
00319    Double_t ddb = fDirInit[0]*fB[0]+fDirInit[1]*fB[1]+fDirInit[2]*fB[2];
00320    if ((1.-TMath::Abs(ddb))<TGeoShape::Tolerance() || TMath::Abs(fC)<TGeoShape::Tolerance()) {
00321       // helix is just a straigth line
00322       TObject::SetBit(kHelixStraigth, kTRUE);
00323       fMatrix->Clear();
00324       return;
00325    }   
00326    rot[2] = fB[0];
00327    rot[5] = fB[1];
00328    rot[8] = fB[2];
00329    if (ddb < 0) fS = -TMath::Abs(fS);
00330    Double_t fy = - fQ*TMath::Sqrt(1.-ddb*ddb);
00331    fy = 1./fy;
00332    rot[1] = fy*(fDirInit[0]-fB[0]*ddb);
00333    rot[4] = fy*(fDirInit[1]-fB[1]*ddb);
00334    rot[7] = fy*(fDirInit[2]-fB[2]*ddb);
00335 
00336    rot[0] = rot[4]*rot[8] - rot[7]*rot[5];
00337    rot[3] = rot[7]*rot[2] - rot[1]*rot[8];
00338    rot[6] = rot[1]*rot[5] - rot[4]*rot[2];
00339    
00340    tr[0] = fPointInit[0] - rot[0]/fC;
00341    tr[1] = fPointInit[1] - rot[3]/fC;
00342    tr[2] = fPointInit[2] - rot[6]/fC;
00343    
00344    fMatrix->SetTranslation(tr);
00345    fMatrix->SetRotation(rot);
00346    
00347 }    

Generated on Tue Jul 5 14:12:55 2011 for ROOT_528-00b_version by  doxygen 1.5.1