]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrackExtrap.cxx
Adding includes required by ROOT
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackExtrap.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////
19 //
20 // Tools
21 // for
22 // track
23 // extrapolation
24 // in
25 // ALICE
26 // dimuon
27 // spectrometer
28 //
29 ///////////////////////////////////////////////////
30
31 #include <Riostream.h>
32 #include <TMath.h>
33 #include <TMatrixD.h>
34
35 #include "AliMUONTrackExtrap.h" 
36 #include "AliMUONTrackParam.h"
37 #include "AliMUONConstants.h"
38 #include "AliMagF.h" 
39 #include "AliLog.h" 
40 #include "AliTracker.h"
41
42 ClassImp(AliMUONTrackExtrap) // Class implementation in ROOT context
43
44 const AliMagF* AliMUONTrackExtrap::fgkField = 0x0;
45 const Int_t    AliMUONTrackExtrap::fgkMaxStepNumber = 5000;
46 const Double_t AliMUONTrackExtrap::fgkStepLength = 6.;
47
48   //__________________________________________________________________________
49 Double_t AliMUONTrackExtrap::GetImpactParamFromBendingMomentum(Double_t bendingMomentum)
50 {
51   /// Returns impact parameter at vertex in bending plane (cm),
52   /// from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
53   /// using simple values for dipole magnetic field.
54   /// The sign of "BendingMomentum" is the sign of the charge.
55   
56   if (bendingMomentum == 0.) return 1.e10;
57   
58   Double_t simpleBPosition = 0.5 * (AliMUONConstants::CoilZ() + AliMUONConstants::YokeZ());
59   Double_t simpleBLength = 0.5 * (AliMUONConstants::CoilL() + AliMUONConstants::YokeL());
60   Float_t b[3], x[3] = {0.,0.,(Float_t) simpleBPosition};
61   if (fgkField) fgkField->Field(x,b);
62   else {
63     cout<<"F-AliMUONTrackExtrap::GetField: fgkField = 0x0"<<endl;
64     exit(-1);
65   }
66   Double_t simpleBValue = (Double_t) b[0];
67   
68   return (-0.0003 * simpleBValue * simpleBLength * simpleBPosition / bendingMomentum);
69 }
70
71   //__________________________________________________________________________
72 Double_t AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(Double_t impactParam)
73 {
74   /// Returns signed bending momentum in bending plane (GeV/c),
75   /// the sign being the sign of the charge for particles moving forward in Z,
76   /// from the impact parameter "ImpactParam" at vertex in bending plane (cm),
77   /// using simple values for dipole magnetic field.
78   
79   if (impactParam == 0.) return 1.e10;
80   
81   Double_t simpleBPosition = 0.5 * (AliMUONConstants::CoilZ() + AliMUONConstants::YokeZ());
82   Double_t simpleBLength = 0.5 * (AliMUONConstants::CoilL() + AliMUONConstants::YokeL());
83   Float_t b[3], x[3] = {0.,0.,(Float_t) simpleBPosition};
84   if (fgkField) fgkField->Field(x,b);
85   else {
86     cout<<"F-AliMUONTrackExtrap::GetField: fgkField = 0x0"<<endl;
87     exit(-1);
88   }
89   Double_t simpleBValue = (Double_t) b[0];
90   
91   return (-0.0003 * simpleBValue * simpleBLength * simpleBPosition / impactParam);
92 }
93
94   //__________________________________________________________________________
95 void AliMUONTrackExtrap::ExtrapToZ(AliMUONTrackParam* trackParam, Double_t zEnd)
96 {
97   /// Track parameter extrapolation to the plane at "Z".
98   /// On return, the track parameters resulting from the extrapolation are updated in trackParam.
99   if (trackParam->GetZ() == zEnd) return; // nothing to be done if same Z
100   Double_t forwardBackward; // +1 if forward, -1 if backward
101   if (zEnd < trackParam->GetZ()) forwardBackward = 1.0; // spectro. z<0 
102   else forwardBackward = -1.0;
103   Double_t v3[7], v3New[7]; // 7 in parameter ????
104   Int_t i3, stepNumber;
105   // For safety: return kTRUE or kFALSE ????
106   // Parameter vector for calling EXTRAP_ONESTEP
107   ConvertTrackParamForExtrap(trackParam, v3, forwardBackward);
108   // sign of charge (sign of fInverseBendingMomentum if forward motion)
109   // must be changed if backward extrapolation
110   Double_t chargeExtrap = forwardBackward * TMath::Sign(Double_t(1.0), trackParam->GetInverseBendingMomentum());
111   // Extrapolation loop
112   stepNumber = 0;
113   while (((-forwardBackward * (v3[2] - zEnd)) <= 0.0) && (stepNumber < fgkMaxStepNumber)) { // spectro. z<0
114     stepNumber++;
115     // Option for switching between helix and Runge-Kutta ???? 
116     //ExtrapOneStepRungekutta(chargeExtrap, fgkStepLength, v3, v3New);
117     ExtrapOneStepHelix(chargeExtrap, fgkStepLength, v3, v3New);
118     if ((-forwardBackward * (v3New[2] - zEnd)) > 0.0) break; // one is beyond Z spectro. z<0
119     // better use TArray ????
120     for (i3 = 0; i3 < 7; i3++) {v3[i3] = v3New[i3];}
121   }
122   // check fgkMaxStepNumber ????
123   // Interpolation back to exact Z (2nd order)
124   // should be in function ???? using TArray ????
125   Double_t dZ12 = v3New[2] - v3[2]; // 1->2
126   if (TMath::Abs(dZ12) > 0) {
127     Double_t dZ1i = zEnd - v3[2]; // 1-i
128     Double_t dZi2 = v3New[2] - zEnd; // i->2
129     Double_t xPrime = (v3New[0] - v3[0]) / dZ12;
130     Double_t xSecond = ((v3New[3] / v3New[5]) - (v3[3] / v3[5])) / dZ12;
131     Double_t yPrime = (v3New[1] - v3[1]) / dZ12;
132     Double_t ySecond = ((v3New[4] / v3New[5]) - (v3[4] / v3[5])) / dZ12;
133     v3[0] = v3[0] + xPrime * dZ1i - 0.5 * xSecond * dZ1i * dZi2; // X
134     v3[1] = v3[1] + yPrime * dZ1i - 0.5 * ySecond * dZ1i * dZi2; // Y
135     v3[2] = zEnd; // Z
136     Double_t xPrimeI = xPrime - 0.5 * xSecond * (dZi2 - dZ1i);
137     Double_t yPrimeI = yPrime - 0.5 * ySecond * (dZi2 - dZ1i);
138     // (PX, PY, PZ)/PTOT assuming forward motion
139     v3[5] = 1.0 / TMath::Sqrt(1.0 + xPrimeI * xPrimeI + yPrimeI * yPrimeI); // PZ/PTOT
140     v3[3] = xPrimeI * v3[5]; // PX/PTOT
141     v3[4] = yPrimeI * v3[5]; // PY/PTOT
142   } else {
143     cout<<"W-AliMUONTrackExtrap::ExtrapToZ: Extrap. to Z not reached, Z = "<<zEnd<<endl;
144   }
145   // Track parameters from 3 parameters,
146   // with charge back for forward motion
147   RecoverTrackParam(v3, chargeExtrap * forwardBackward, trackParam);
148 }
149
150   //__________________________________________________________________________
151 void AliMUONTrackExtrap::ConvertTrackParamForExtrap(AliMUONTrackParam* trackParam, Double_t *v3, Double_t forwardBackward)
152 {
153   /// Set vector of Geant3 parameters pointed to by "v3" from track parameters in trackParam.
154   /// Since AliMUONTrackParam is only geometry, one uses "forwardBackward"
155   /// to know whether the particle is going forward (+1) or backward (-1).
156   v3[0] = trackParam->GetNonBendingCoor(); // X
157   v3[1] = trackParam->GetBendingCoor(); // Y
158   v3[2] = trackParam->GetZ(); // Z
159   Double_t pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
160   Double_t pZ = pYZ / TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope());
161   v3[6] = TMath::Sqrt(pYZ * pYZ + pZ * pZ * trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()); // PTOT
162   v3[5] = -forwardBackward * pZ / v3[6]; // PZ/PTOT spectro. z<0
163   v3[3] = trackParam->GetNonBendingSlope() * v3[5]; // PX/PTOT
164   v3[4] = trackParam->GetBendingSlope() * v3[5]; // PY/PTOT
165 }
166
167   //__________________________________________________________________________
168 void AliMUONTrackExtrap::RecoverTrackParam(Double_t *v3, Double_t charge, AliMUONTrackParam* trackParam)
169 {
170   /// Set track parameters in trackParam from Geant3 parameters pointed to by "v3",
171   /// assumed to be calculated for forward motion in Z.
172   /// "InverseBendingMomentum" is signed with "charge".
173   trackParam->SetNonBendingCoor(v3[0]); // X
174   trackParam->SetBendingCoor(v3[1]); // Y
175   trackParam->SetZ(v3[2]); // Z
176   Double_t pYZ = v3[6] * TMath::Sqrt(1.0 - v3[3] * v3[3]);
177   trackParam->SetInverseBendingMomentum(charge/pYZ);
178   trackParam->SetBendingSlope(v3[4]/v3[5]);
179   trackParam->SetNonBendingSlope(v3[3]/v3[5]);
180 }
181
182   //__________________________________________________________________________
183 void AliMUONTrackExtrap::ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd)
184 {
185   /// Track parameters and their covariances extrapolated to the plane at "zEnd".
186   /// On return, results from the extrapolation are updated in trackParam.
187   
188   if (trackParam->GetZ() == zEnd) return; // nothing to be done if same z
189   
190   // Save the actual track parameters
191   AliMUONTrackParam trackParamSave(*trackParam);
192   Double_t nonBendingCoor         = trackParamSave.GetNonBendingCoor();
193   Double_t nonBendingSlope        = trackParamSave.GetNonBendingSlope();
194   Double_t bendingCoor            = trackParamSave.GetBendingCoor();
195   Double_t bendingSlope           = trackParamSave.GetBendingSlope();
196   Double_t inverseBendingMomentum = trackParamSave.GetInverseBendingMomentum();
197   Double_t zBegin                 = trackParamSave.GetZ();
198   
199   // Extrapolate track parameters to "zEnd"
200   ExtrapToZ(trackParam,zEnd);
201   Double_t extrapNonBendingCoor         = trackParam->GetNonBendingCoor();
202   Double_t extrapNonBendingSlope        = trackParam->GetNonBendingSlope();
203   Double_t extrapBendingCoor            = trackParam->GetBendingCoor();
204   Double_t extrapBendingSlope           = trackParam->GetBendingSlope();
205   Double_t extrapInverseBendingMomentum = trackParam->GetInverseBendingMomentum();
206   
207   // Get the pointer to the parameter covariance matrix
208   if (!trackParam->CovariancesExist()) {
209     //cout<<"W-AliMUONTrackExtrap::ExtrapToZCov: track parameter covariance matrix does not exist"<<endl;
210     //cout<<"                                    -> nothing to extrapolate !!"<<endl;
211     return;
212   }
213   TMatrixD* paramCov = trackParam->GetCovariances();
214   
215   // Calculate the jacobian related to the track parameters extrapolation to "zEnd"
216   TMatrixD jacob(5,5);
217   jacob = 0.;
218   Double_t dParam[5];
219   for (Int_t i=0; i<5; i++) {
220     // Skip jacobian calculation for parameters with no associated error
221     if ((*paramCov)(i,i) == 0.) continue;
222     // Small variation of parameter i only
223     for (Int_t j=0; j<5; j++) {
224       if (j==i) {
225         dParam[j] = TMath::Sqrt((*paramCov)(i,i));
226         if (j == 4) dParam[j] *= TMath::Sign(1.,-inverseBendingMomentum); // variation always in the same direction
227       } else dParam[j] = 0.;
228     }
229     // Set new parameters
230     trackParamSave.SetNonBendingCoor        (nonBendingCoor         + dParam[0]);
231     trackParamSave.SetNonBendingSlope       (nonBendingSlope        + dParam[1]);
232     trackParamSave.SetBendingCoor           (bendingCoor            + dParam[2]);
233     trackParamSave.SetBendingSlope          (bendingSlope           + dParam[3]);
234     trackParamSave.SetInverseBendingMomentum(inverseBendingMomentum + dParam[4]);
235     trackParamSave.SetZ                     (zBegin);
236     // Extrapolate new track parameters to "zEnd"
237     ExtrapToZ(&trackParamSave,zEnd);
238     // Calculate the jacobian
239     jacob(0,i) = (trackParamSave.GetNonBendingCoor()         - extrapNonBendingCoor        ) / dParam[i];
240     jacob(1,i) = (trackParamSave.GetNonBendingSlope()        - extrapNonBendingSlope       ) / dParam[i];
241     jacob(2,i) = (trackParamSave.GetBendingCoor()            - extrapBendingCoor           ) / dParam[i];
242     jacob(3,i) = (trackParamSave.GetBendingSlope()           - extrapBendingSlope          ) / dParam[i];
243     jacob(4,i) = (trackParamSave.GetInverseBendingMomentum() - extrapInverseBendingMomentum) / dParam[i];
244   }
245   
246   // Extrapolate track parameter covariances to "zEnd"
247   TMatrixD tmp((*paramCov),TMatrixD::kMultTranspose,jacob);
248   (*paramCov) = TMatrixD(jacob,TMatrixD::kMult,tmp);
249   
250 }
251
252   //__________________________________________________________________________
253 void AliMUONTrackExtrap::ExtrapToStation(AliMUONTrackParam* trackParamIn, Int_t station, AliMUONTrackParam *trackParamOut)
254 {
255   /// Track parameters extrapolated from "trackParamIn" to both chambers of the station(0..) "station"
256   /// are returned in the array (dimension 2) of track parameters pointed to by "TrackParamOut"
257   /// (index 0 and 1 for first and second chambers).
258   Double_t extZ[2], z1, z2;
259   Int_t i1 = -1, i2 = -1; // = -1 to avoid compilation warnings
260   // range of station to be checked ????
261   z1 = AliMUONConstants::DefaultChamberZ(2 * station);
262   z2 = AliMUONConstants::DefaultChamberZ(2 * station + 1);
263   // First and second Z to extrapolate at
264   if ((z1 > trackParamIn->GetZ()) && (z2 > trackParamIn->GetZ())) {i1 = 0; i2 = 1;}
265   else if ((z1 < trackParamIn->GetZ()) && (z2 < trackParamIn->GetZ())) {i1 = 1; i2 = 0;}
266   else {
267     cout<<"E-AliMUONTrackExtrap::ExtrapToStation: Starting Z ("<<trackParamIn->GetZ()
268         <<") in between z1 ("<<z1<<") and z2 ("<<z2<<") of station(0..)"<<station<<endl;
269     exit(-1);
270   }
271   extZ[i1] = z1;
272   extZ[i2] = z2;
273   // copy of track parameters
274   trackParamOut[i1] = *trackParamIn;
275   // first extrapolation
276   ExtrapToZ(&(trackParamOut[i1]),extZ[0]);
277   trackParamOut[i2] = trackParamOut[i1];
278   // second extrapolation
279   ExtrapToZ(&(trackParamOut[i2]),extZ[1]);
280   return;
281 }
282
283   //__________________________________________________________________________
284 void AliMUONTrackExtrap::ExtrapToVertexUncorrected(AliMUONTrackParam* trackParam, Double_t zVtx)
285 {
286   /// Extrapolation to the vertex (at the z position "zVtx") without Branson and Field correction.
287   /// Returns the track parameters resulting from the extrapolation in the current TrackParam.
288   /// Include multiple Coulomb scattering effects in trackParam covariances.
289   
290   if (trackParam->GetZ() > zVtx) { // spectro. (z<0)
291     cout<<"W-AliMUONTrackExtrap::ExtrapToVertexUncorrected: Starting Z ("<<trackParam->GetZ()
292         <<") upstream the vertex (zVtx = "<<zVtx<<")"<<endl;
293     exit(-1);
294   }
295   
296   if (zVtx < AliMUONConstants::ZAbsorberEnd()) { // spectro. (z<0)
297     cout<<"W-AliMUONTrackExtrap::ExtrapToVertexUncorrected: Ending Z ("<<zVtx
298         <<") downstream the front absorber (zAbsorberEnd = "<<AliMUONConstants::ZAbsorberEnd()<<")"<<endl;
299     
300     ExtrapToZCov(trackParam,zVtx);
301     return;
302   }
303   
304   // First Extrapolates track parameters upstream to the "Z" end of the front absorber
305   if (trackParam->GetZ() < AliMUONConstants::ZAbsorberEnd()) { // spectro. (z<0)
306     ExtrapToZCov(trackParam,AliMUONConstants::ZAbsorberEnd());
307   } else {
308     cout<<"W-AliMUONTrackExtrap::ExtrapToVertexUncorrected: Starting Z ("<<trackParam->GetZ()
309         <<") upstream or inside the front absorber (zAbsorberEnd = "<<AliMUONConstants::ZAbsorberEnd()<<")"<<endl;
310   }
311   
312   // Then go through all the absorber layers
313   Double_t tan3 = TMath::Tan(3./180.*TMath::Pi());
314   Double_t r0Norm, x0, z, zElement, dZ, nonBendingCoor, bendingCoor;
315   for (Int_t iElement=AliMUONConstants::NAbsorberElements()-1; iElement>=0; iElement--) {
316     zElement = AliMUONConstants::ZAbsorberElement(iElement);
317     z = trackParam->GetZ();
318     if (z > zElement) continue; // spectro. (z<0)
319     nonBendingCoor = trackParam->GetNonBendingCoor();
320     bendingCoor = trackParam->GetBendingCoor();
321     r0Norm = nonBendingCoor * nonBendingCoor + bendingCoor * bendingCoor;
322     r0Norm  = TMath::Sqrt(r0Norm) / TMath::Abs(trackParam->GetZ()) / tan3;
323     if (r0Norm > 1.) x0 = AliMUONConstants::X0AbsorberOut(iElement); // outer part of the absorber
324     else x0 = AliMUONConstants::X0AbsorberIn(iElement); // inner part of the absorber
325     
326     if (zVtx > zElement) {
327       ExtrapToZCov(trackParam,zElement); // extrapolate to absorber element "iElement"
328       dZ = zElement - z;
329       AddMCSEffectInTrackParamCov(trackParam,dZ,x0); // include MCS effect in covariances
330     } else {
331       ExtrapToZCov(trackParam,zVtx); // extrapolate to zVtx
332       dZ = zVtx - z;
333       AddMCSEffectInTrackParamCov(trackParam,dZ,x0); // include MCS effect in covariances
334       break;
335     }
336   }
337   
338   // finally go to the vertex
339   ExtrapToZCov(trackParam,zVtx);
340   
341 }
342
343   //__________________________________________________________________________
344 void AliMUONTrackExtrap::AddMCSEffectInTrackParamCov(AliMUONTrackParam *param, Double_t dZ, Double_t x0)
345 {
346   /// Add to the track parameter covariances the effects of multiple Coulomb scattering
347   /// through a material of thickness "dZ" and of radiation length "x0"
348   /// assuming linear propagation and using the small angle approximation.
349   
350   Double_t bendingSlope = param->GetBendingSlope();
351   Double_t nonBendingSlope = param->GetNonBendingSlope();
352   Double_t inverseTotalMomentum2 = param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum() *
353                                    (1.0 + bendingSlope * bendingSlope) /
354                                    (1.0 + bendingSlope *bendingSlope + nonBendingSlope * nonBendingSlope); 
355   // Path length in the material
356   Double_t pathLength = TMath::Abs(dZ) * TMath::Sqrt(1.0 + bendingSlope*bendingSlope + nonBendingSlope*nonBendingSlope);
357   Double_t pathLength2 = pathLength * pathLength;
358   // relativistic velocity
359   Double_t velo = 1.;
360   // Angular dispersion square of the track (variance) in a plane perpendicular to the trajectory
361   Double_t theta02 = 0.0136 / velo * (1 + 0.038 * TMath::Log(pathLength/x0));
362   theta02 *= theta02 * inverseTotalMomentum2 * pathLength / x0;
363   
364   // Add effects of multiple Coulomb scattering in track parameter covariances
365   TMatrixD* paramCov = param->GetCovariances();
366   Double_t varCoor      = pathLength2 * theta02 / 3.;
367   Double_t varSlop      = theta02;
368   Double_t covCorrSlope = pathLength * theta02 / 2.;
369   // Non bending plane
370   (*paramCov)(0,0) += varCoor;          (*paramCov)(0,1) += covCorrSlope;
371   (*paramCov)(1,0) += covCorrSlope;     (*paramCov)(1,1) += varSlop;
372   // Bending plane
373   (*paramCov)(2,2) += varCoor;          (*paramCov)(2,3) += covCorrSlope;
374   (*paramCov)(3,2) += covCorrSlope;     (*paramCov)(3,3) += varSlop;
375   
376 }
377
378   //__________________________________________________________________________
379 void AliMUONTrackExtrap::ExtrapToVertex(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx)
380 {
381   /// Extrapolation to the vertex.
382   /// Returns the track parameters resulting from the extrapolation in the current TrackParam.
383   /// Changes parameters according to Branson correction through the absorber 
384   
385   // Extrapolates track parameters upstream to the "Z" end of the front absorber
386   ExtrapToZ(trackParam,AliMUONConstants::ZAbsorberEnd()); // !!!
387   // Makes Branson correction (multiple scattering + energy loss)
388   BransonCorrection(trackParam,xVtx,yVtx,zVtx);
389   // Makes a simple magnetic field correction through the absorber
390   FieldCorrection(trackParam,AliMUONConstants::ZAbsorberEnd());
391 }
392
393
394 //  Keep this version for future developments
395   //__________________________________________________________________________
396 // void AliMUONTrackExtrap::BransonCorrection(AliMUONTrackParam* trackParam)
397 // {
398 //   /// Branson correction of track parameters
399 //   // the entry parameters have to be calculated at the end of the absorber
400 //   Double_t zEndAbsorber, zBP, xBP, yBP;
401 //   Double_t  pYZ, pX, pY, pZ, pTotal, xEndAbsorber, yEndAbsorber, radiusEndAbsorber2, pT, theta;
402 //   Int_t sign;
403 //   // Would it be possible to calculate all that from Geant configuration ????
404 //   // and to get the Branson parameters from a function in ABSO module ????
405 //   // with an eventual contribution from other detectors like START ????
406 //   // Radiation lengths outer part theta > 3 degres
407 //   static Double_t x01[9] = { 18.8,    // C (cm)
408 //                           10.397,   // Concrete (cm)
409 //                           0.56,    // Plomb (cm)
410 //                           47.26,   // Polyethylene (cm)
411 //                           0.56,   // Plomb (cm)
412 //                           47.26,   // Polyethylene (cm)
413 //                           0.56,   // Plomb (cm)
414 //                           47.26,   // Polyethylene (cm)
415 //                           0.56 };   // Plomb (cm)
416 //   // inner part theta < 3 degres
417 //   static Double_t x02[3] = { 18.8,    // C (cm)
418 //                           10.397,   // Concrete (cm)
419 //                           0.35 };    // W (cm) 
420 //   // z positions of the materials inside the absober outer part theta > 3 degres
421 //   static Double_t z1[10] = { 90, 315, 467, 472, 477, 482, 487, 492, 497, 502 };
422 //   // inner part theta < 3 degres
423 //   static Double_t z2[4] = { 90, 315, 467, 503 };
424 //   static Bool_t first = kTRUE;
425 //   static Double_t zBP1, zBP2, rLimit;
426 //   // Calculates z positions of the Branson's planes: zBP1 for outer part and zBP2 for inner part (only at the first call)
427 //   if (first) {
428 //     first = kFALSE;
429 //     Double_t aNBP = 0.0;
430 //     Double_t aDBP = 0.0;
431 //     Int_t iBound;
432 //     
433 //     for (iBound = 0; iBound < 9; iBound++) {
434 //       aNBP = aNBP +
435 //      (z1[iBound+1] * z1[iBound+1] * z1[iBound+1] -
436 //       z1[iBound]   * z1[iBound]   * z1[iBound]    ) / x01[iBound];
437 //       aDBP = aDBP +
438 //      (z1[iBound+1] * z1[iBound+1] - z1[iBound]   * z1[iBound]    ) / x01[iBound];
439 //     }
440 //     zBP1 = (2.0 * aNBP) / (3.0 * aDBP);
441 //     aNBP = 0.0;
442 //     aDBP = 0.0;
443 //     for (iBound = 0; iBound < 3; iBound++) {
444 //       aNBP = aNBP +
445 //      (z2[iBound+1] * z2[iBound+1] * z2[iBound+1] -
446 //       z2[iBound]   * z2[iBound ]  * z2[iBound]    ) / x02[iBound];
447 //       aDBP = aDBP +
448 //      (z2[iBound+1] * z2[iBound+1] - z2[iBound] * z2[iBound]) / x02[iBound];
449 //     }
450 //     zBP2 = (2.0 * aNBP) / (3.0 * aDBP);
451 //     rLimit = z2[3] * TMath::Tan(3.0 * (TMath::Pi()) / 180.);
452 //   }
453 // 
454 //   pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
455 //   sign = 1;      
456 //   if (trackParam->GetInverseBendingMomentum() < 0) sign = -1;     
457 //   pZ = pYZ / (TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope())); 
458 //   pX = pZ * trackParam->GetNonBendingSlope(); 
459 //   pY = pZ * trackParam->GetBendingSlope(); 
460 //   pTotal = TMath::Sqrt(pYZ *pYZ + pX * pX);
461 //   xEndAbsorber = trackParam->GetNonBendingCoor(); 
462 //   yEndAbsorber = trackParam->GetBendingCoor(); 
463 //   radiusEndAbsorber2 = xEndAbsorber * xEndAbsorber + yEndAbsorber * yEndAbsorber;
464 // 
465 //   if (radiusEndAbsorber2 > rLimit*rLimit) {
466 //     zEndAbsorber = z1[9];
467 //     zBP = zBP1;
468 //   } else {
469 //     zEndAbsorber = z2[3];
470 //     zBP = zBP2;
471 //   }
472 // 
473 //   xBP = xEndAbsorber - (pX / pZ) * (zEndAbsorber - zBP);
474 //   yBP = yEndAbsorber - (pY / pZ) * (zEndAbsorber - zBP);
475 // 
476 //   // new parameters after Branson and energy loss corrections
477 //   pZ = pTotal * zBP / TMath::Sqrt(xBP * xBP + yBP * yBP + zBP * zBP);
478 //   pX = pZ * xBP / zBP;
479 //   pY = pZ * yBP / zBP;
480 //   trackParam->SetBendingSlope(pY/pZ);
481 //   trackParam->SetNonBendingSlope(pX/pZ);
482 //   
483 //   pT = TMath::Sqrt(pX * pX + pY * pY);      
484 //   theta = TMath::ATan2(pT, pZ); 
485 //   pTotal = TotalMomentumEnergyLoss(rLimit, pTotal, theta, xEndAbsorber, yEndAbsorber);
486 // 
487 //   trackParam->SetInverseBendingMomentum((sign / pTotal) *
488 //     TMath::Sqrt(1.0 +
489 //              trackParam->GetBendingSlope() * trackParam->GetBendingSlope() +
490 //              trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()) /
491 //     TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope()));
492 // 
493 //   // vertex position at (0,0,0)
494 //   // should be taken from vertex measurement ???
495 //   trackParam->SetBendingCoor(0.);
496 //   trackParam->SetNonBendingCoor(0.);
497 //   trackParam->SetZ(0.);
498 // }
499
500 void AliMUONTrackExtrap::BransonCorrection(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx)
501 {
502   /// Branson correction of track parameters
503   // the entry parameters have to be calculated at the end of the absorber
504   // simplified version: the z positions of Branson's planes are no longer calculated
505   // but are given as inputs. One can use the macros MUONTestAbso.C and DrawTestAbso.C
506   // to test this correction. 
507   // Would it be possible to calculate all that from Geant configuration ????
508   // and to get the Branson parameters from a function in ABSO module ????
509   // with an eventual contribution from other detectors like START ????
510   // change to take into account the vertex postition (real, reconstruct,....)
511
512   Double_t  zBP, xBP, yBP;
513   Double_t  pYZ, pX, pY, pZ, pTotal, xEndAbsorber, yEndAbsorber, radiusEndAbsorber2, pT, theta;
514   Int_t sign;
515   static Bool_t first = kTRUE;
516   static Double_t zBP1, zBP2, rLimit, thetaLimit;
517   // zBP1 for outer part and zBP2 for inner part (only at the first call)
518   if (first) {
519     first = kFALSE;
520   
521     thetaLimit = 3.0 * (TMath::Pi()) / 180.;
522     rLimit = TMath::Abs(AliMUONConstants::ZAbsorberEnd()) * TMath::Tan(thetaLimit);
523     zBP1 = -450; // values close to those calculated with EvalAbso.C
524     zBP2 = -480;
525   }
526
527   pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
528   sign = 1;      
529   if (trackParam->GetInverseBendingMomentum() < 0) sign = -1;  
530   pZ = trackParam->Pz();
531   pX = trackParam->Px(); 
532   pY = trackParam->Py(); 
533   pTotal = TMath::Sqrt(pYZ *pYZ + pX * pX);
534   xEndAbsorber = trackParam->GetNonBendingCoor(); 
535   yEndAbsorber = trackParam->GetBendingCoor(); 
536   radiusEndAbsorber2 = xEndAbsorber * xEndAbsorber + yEndAbsorber * yEndAbsorber;
537
538   if (radiusEndAbsorber2 > rLimit*rLimit) {
539     zBP = zBP1;
540   } else {
541     zBP = zBP2;
542   }
543
544   xBP = xEndAbsorber - (pX / pZ) * (AliMUONConstants::ZAbsorberEnd() - zBP);
545   yBP = yEndAbsorber - (pY / pZ) * (AliMUONConstants::ZAbsorberEnd() - zBP);
546
547   // new parameters after Branson and energy loss corrections
548 //   Float_t zSmear = zBP - gRandom->Gaus(0.,2.);  // !!! possible smearing of Z vertex position
549
550   Float_t zSmear = zBP ;
551   
552   pZ = pTotal * (zSmear-zVtx) / TMath::Sqrt((xBP-xVtx) * (xBP-xVtx) + (yBP-yVtx) * (yBP-yVtx) +( zSmear-zVtx) * (zSmear-zVtx) );
553   pX = pZ * (xBP - xVtx)/ (zSmear-zVtx);
554   pY = pZ * (yBP - yVtx) / (zSmear-zVtx);
555   trackParam->SetBendingSlope(pY/pZ);
556   trackParam->SetNonBendingSlope(pX/pZ);
557
558   
559   pT = TMath::Sqrt(pX * pX + pY * pY);      
560   theta = TMath::ATan2(pT, TMath::Abs(pZ)); 
561   pTotal = TotalMomentumEnergyLoss(thetaLimit, pTotal, theta);
562
563   trackParam->SetInverseBendingMomentum((sign / pTotal) *
564     TMath::Sqrt(1.0 +
565                 trackParam->GetBendingSlope() * trackParam->GetBendingSlope() +
566                 trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()) /
567     TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope()));
568
569   // vertex position at (0,0,0)
570   // should be taken from vertex measurement ???
571
572   trackParam->SetBendingCoor(xVtx);
573   trackParam->SetNonBendingCoor(yVtx);
574   trackParam->SetZ(zVtx);
575
576 }
577
578   //__________________________________________________________________________
579 Double_t AliMUONTrackExtrap::TotalMomentumEnergyLoss(Double_t thetaLimit, Double_t pTotal, Double_t theta)
580 {
581   /// Returns the total momentum corrected from energy loss in the front absorber
582   // One can use the macros MUONTestAbso.C and DrawTestAbso.C
583   // to test this correction. 
584   // Momentum energy loss behaviour evaluated with the simulation of single muons (april 2002)
585   Double_t deltaP, pTotalCorrected;
586
587    // Parametrization to be redone according to change of absorber material ????
588   // See remark in function BransonCorrection !!!!
589   // The name is not so good, and there are many arguments !!!!
590   if (theta  < thetaLimit ) {
591     if (pTotal < 20) {
592       deltaP = 2.5938 + 0.0570 * pTotal - 0.001151 * pTotal * pTotal;
593     } else {
594       deltaP = 3.0714 + 0.011767 *pTotal;
595     }
596     deltaP *= 0.75; // AZ
597   } else {
598     if (pTotal < 20) {
599       deltaP  = 2.1207 + 0.05478 * pTotal - 0.00145079 * pTotal * pTotal;
600     } else { 
601       deltaP = 2.6069 + 0.0051705 * pTotal;
602     }
603     deltaP *= 0.9; // AZ
604   }
605   pTotalCorrected = pTotal + deltaP / TMath::Cos(theta);
606   return pTotalCorrected;
607 }
608
609   //__________________________________________________________________________
610 void AliMUONTrackExtrap::FieldCorrection(AliMUONTrackParam *trackParam, Double_t zEnd)
611 {
612   /// Correction of the effect of the magnetic field in the absorber
613   // Assume a constant field along Z axis.
614   Float_t b[3],x[3]; 
615   Double_t bZ;
616   Double_t pYZ,pX,pY,pZ,pT;
617   Double_t pXNew,pYNew;
618   Double_t c;
619
620   pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
621   c = TMath::Sign(1.0,trackParam->GetInverseBendingMomentum()); // particle charge 
622  
623   pZ = trackParam->Pz();
624   pX = trackParam->Px(); 
625   pY = trackParam->Py();
626   pT = TMath::Sqrt(pX*pX+pY*pY);
627
628   if (TMath::Abs(pZ) <= 0) return;
629   x[2] = zEnd/2;
630   x[0] = x[2]*trackParam->GetNonBendingSlope();  
631   x[1] = x[2]*trackParam->GetBendingSlope();
632
633   // Take magn. field value at position x.
634   if (fgkField) fgkField->Field(x,b);
635   else {
636     cout<<"F-AliMUONTrackExtrap::FieldCorrection: fgkField = 0x0"<<endl;
637     exit(-1);
638   }
639   bZ =  b[2];
640  
641   // Transverse momentum rotation
642   // Parameterized with the study of DeltaPhi = phiReco - phiGen as a function of pZ.
643   Double_t phiShift = c*0.436*0.0003*bZ*zEnd/pZ; 
644  // Rotate momentum around Z axis.
645   pXNew = pX*TMath::Cos(phiShift) - pY*TMath::Sin(phiShift);
646   pYNew = pX*TMath::Sin(phiShift) + pY*TMath::Cos(phiShift);
647  
648   trackParam->SetBendingSlope(pYNew/pZ);
649   trackParam->SetNonBendingSlope(pXNew/pZ);
650   
651   trackParam->SetInverseBendingMomentum(c/TMath::Sqrt(pYNew*pYNew+pZ*pZ));
652  
653 }
654
655  //__________________________________________________________________________
656 void AliMUONTrackExtrap::ExtrapOneStepHelix(Double_t charge, Double_t step, Double_t *vect, Double_t *vout)
657 {
658 ///    ******************************************************************
659 ///    *                                                                *
660 ///    *  Performs the tracking of one step in a magnetic field         *
661 ///    *  The trajectory is assumed to be a helix in a constant field   *
662 ///    *  taken at the mid point of the step.                           *
663 ///    *  Parameters:                                                   *
664 ///    *   input                                                        *
665 ///    *     STEP =arc length of the step asked                         *
666 ///    *     VECT =input vector (position,direction cos and momentum)   *
667 ///    *     CHARGE=  electric charge of the particle                   *
668 ///    *   output                                                       *
669 ///    *     VOUT = same as VECT after completion of the step           *
670 ///    *                                                                *
671 ///    *    ==>Called by : <USER>, GUSWIM                               *
672 ///    *       Author    m.hansroul  *********                          *
673 ///    *       modified  s.egli, s.v.levonian                           *
674 ///    *       modified  v.perevoztchikov
675 ///    *                                                                *
676 ///    ******************************************************************
677
678 // modif: everything in double precision
679
680     Double_t xyz[3], h[4], hxp[3];
681     Double_t h2xy, hp, rho, tet;
682     Double_t sint, sintt, tsint, cos1t;
683     Double_t f1, f2, f3, f4, f5, f6;
684
685     const Int_t kix  = 0;
686     const Int_t kiy  = 1;
687     const Int_t kiz  = 2;
688     const Int_t kipx = 3;
689     const Int_t kipy = 4;
690     const Int_t kipz = 5;
691     const Int_t kipp = 6;
692
693     const Double_t kec = 2.9979251e-4;
694     //
695     //    ------------------------------------------------------------------
696     //
697     //       units are kgauss,centimeters,gev/c
698     //
699     vout[kipp] = vect[kipp];
700     if (TMath::Abs(charge) < 0.00001) {
701       for (Int_t i = 0; i < 3; i++) {
702         vout[i] = vect[i] + step * vect[i+3];
703         vout[i+3] = vect[i+3];
704       }
705       return;
706     }
707     xyz[0]    = vect[kix] + 0.5 * step * vect[kipx];
708     xyz[1]    = vect[kiy] + 0.5 * step * vect[kipy];
709     xyz[2]    = vect[kiz] + 0.5 * step * vect[kipz];
710
711     //cmodif: call gufld (xyz, h) changed into:
712     GetField (xyz, h);
713  
714     h2xy = h[0]*h[0] + h[1]*h[1];
715     h[3] = h[2]*h[2]+ h2xy;
716     if (h[3] < 1.e-12) {
717       for (Int_t i = 0; i < 3; i++) {
718         vout[i] = vect[i] + step * vect[i+3];
719         vout[i+3] = vect[i+3];
720       }
721       return;
722     }
723     if (h2xy < 1.e-12*h[3]) {
724       ExtrapOneStepHelix3(charge*h[2], step, vect, vout);
725       return;
726     }
727     h[3] = TMath::Sqrt(h[3]);
728     h[0] /= h[3];
729     h[1] /= h[3];
730     h[2] /= h[3];
731     h[3] *= kec;
732
733     hxp[0] = h[1]*vect[kipz] - h[2]*vect[kipy];
734     hxp[1] = h[2]*vect[kipx] - h[0]*vect[kipz];
735     hxp[2] = h[0]*vect[kipy] - h[1]*vect[kipx];
736  
737     hp = h[0]*vect[kipx] + h[1]*vect[kipy] + h[2]*vect[kipz];
738
739     rho = -charge*h[3]/vect[kipp];
740     tet = rho * step;
741
742     if (TMath::Abs(tet) > 0.15) {
743       sint = TMath::Sin(tet);
744       sintt = (sint/tet);
745       tsint = (tet-sint)/tet;
746       cos1t = 2.*(TMath::Sin(0.5*tet))*(TMath::Sin(0.5*tet))/tet;
747     } else {
748       tsint = tet*tet/36.;
749       sintt = (1. - tsint);
750       sint = tet*sintt;
751       cos1t = 0.5*tet;
752     }
753
754     f1 = step * sintt;
755     f2 = step * cos1t;
756     f3 = step * tsint * hp;
757     f4 = -tet*cos1t;
758     f5 = sint;
759     f6 = tet * cos1t * hp;
760  
761     vout[kix] = vect[kix] + f1*vect[kipx] + f2*hxp[0] + f3*h[0];
762     vout[kiy] = vect[kiy] + f1*vect[kipy] + f2*hxp[1] + f3*h[1];
763     vout[kiz] = vect[kiz] + f1*vect[kipz] + f2*hxp[2] + f3*h[2];
764  
765     vout[kipx] = vect[kipx] + f4*vect[kipx] + f5*hxp[0] + f6*h[0];
766     vout[kipy] = vect[kipy] + f4*vect[kipy] + f5*hxp[1] + f6*h[1];
767     vout[kipz] = vect[kipz] + f4*vect[kipz] + f5*hxp[2] + f6*h[2];
768  
769     return;
770 }
771
772  //__________________________________________________________________________
773 void AliMUONTrackExtrap::ExtrapOneStepHelix3(Double_t field, Double_t step, Double_t *vect, Double_t *vout)
774 {
775 ///     ******************************************************************
776 ///     *                                                                *
777 ///     *       Tracking routine in a constant field oriented            *
778 ///     *       along axis 3                                             *
779 ///     *       Tracking is performed with a conventional                *
780 ///     *       helix step method                                        *
781 ///     *                                                                *
782 ///     *    ==>Called by : <USER>, GUSWIM                               *
783 ///     *       Authors    R.Brun, M.Hansroul  *********                 *
784 ///     *       Rewritten  V.Perevoztchikov
785 ///     *                                                                *
786 ///     ******************************************************************
787
788     Double_t hxp[3];
789     Double_t h4, hp, rho, tet;
790     Double_t sint, sintt, tsint, cos1t;
791     Double_t f1, f2, f3, f4, f5, f6;
792
793     const Int_t kix  = 0;
794     const Int_t kiy  = 1;
795     const Int_t kiz  = 2;
796     const Int_t kipx = 3;
797     const Int_t kipy = 4;
798     const Int_t kipz = 5;
799     const Int_t kipp = 6;
800
801     const Double_t kec = 2.9979251e-4;
802
803 // 
804 //     ------------------------------------------------------------------
805 // 
806 //       units are kgauss,centimeters,gev/c
807 // 
808     vout[kipp] = vect[kipp];
809     h4 = field * kec;
810
811     hxp[0] = - vect[kipy];
812     hxp[1] = + vect[kipx];
813  
814     hp = vect[kipz];
815
816     rho = -h4/vect[kipp];
817     tet = rho * step;
818     if (TMath::Abs(tet) > 0.15) {
819       sint = TMath::Sin(tet);
820       sintt = (sint/tet);
821       tsint = (tet-sint)/tet;
822       cos1t = 2.* TMath::Sin(0.5*tet) * TMath::Sin(0.5*tet)/tet;
823     } else {
824       tsint = tet*tet/36.;
825       sintt = (1. - tsint);
826       sint = tet*sintt;
827       cos1t = 0.5*tet;
828     }
829
830     f1 = step * sintt;
831     f2 = step * cos1t;
832     f3 = step * tsint * hp;
833     f4 = -tet*cos1t;
834     f5 = sint;
835     f6 = tet * cos1t * hp;
836  
837     vout[kix] = vect[kix] + f1*vect[kipx] + f2*hxp[0];
838     vout[kiy] = vect[kiy] + f1*vect[kipy] + f2*hxp[1];
839     vout[kiz] = vect[kiz] + f1*vect[kipz] + f3;
840  
841     vout[kipx] = vect[kipx] + f4*vect[kipx] + f5*hxp[0];
842     vout[kipy] = vect[kipy] + f4*vect[kipy] + f5*hxp[1];
843     vout[kipz] = vect[kipz] + f4*vect[kipz] + f6;
844
845     return;
846 }
847  //__________________________________________________________________________
848 void AliMUONTrackExtrap::ExtrapOneStepRungekutta(Double_t charge, Double_t step, Double_t* vect, Double_t* vout)
849 {
850 ///     ******************************************************************
851 ///     *                                                                *
852 ///     *  Runge-Kutta method for tracking a particle through a magnetic *
853 ///     *  field. Uses Nystroem algorithm (See Handbook Nat. Bur. of     *
854 ///     *  Standards, procedure 25.5.20)                                 *
855 ///     *                                                                *
856 ///     *  Input parameters                                              *
857 ///     *       CHARGE    Particle charge                                *
858 ///     *       STEP      Step size                                      *
859 ///     *       VECT      Initial co-ords,direction cosines,momentum     *
860 ///     *  Output parameters                                             *
861 ///     *       VOUT      Output co-ords,direction cosines,momentum      *
862 ///     *  User routine called                                           *
863 ///     *       CALL GUFLD(X,F)                                          *
864 ///     *                                                                *
865 ///     *    ==>Called by : <USER>, GUSWIM                               *
866 ///     *       Authors    R.Brun, M.Hansroul  *********                 *
867 ///     *                  V.Perevoztchikov (CUT STEP implementation)    *
868 ///     *                                                                *
869 ///     *                                                                *
870 ///     ******************************************************************
871
872     Double_t h2, h4, f[4];
873     Double_t xyzt[3], a, b, c, ph,ph2;
874     Double_t secxs[4],secys[4],seczs[4],hxp[3];
875     Double_t g1, g2, g3, g4, g5, g6, ang2, dxt, dyt, dzt;
876     Double_t est, at, bt, ct, cba;
877     Double_t f1, f2, f3, f4, rho, tet, hnorm, hp, rho1, sint, cost;
878     
879     Double_t x;
880     Double_t y;
881     Double_t z;
882     
883     Double_t xt;
884     Double_t yt;
885     Double_t zt;
886
887     Double_t maxit = 1992;
888     Double_t maxcut = 11;
889
890     const Double_t kdlt   = 1e-4;
891     const Double_t kdlt32 = kdlt/32.;
892     const Double_t kthird = 1./3.;
893     const Double_t khalf  = 0.5;
894     const Double_t kec = 2.9979251e-4;
895
896     const Double_t kpisqua = 9.86960440109;
897     const Int_t kix  = 0;
898     const Int_t kiy  = 1;
899     const Int_t kiz  = 2;
900     const Int_t kipx = 3;
901     const Int_t kipy = 4;
902     const Int_t kipz = 5;
903   
904     // *.
905     // *.    ------------------------------------------------------------------
906     // *.
907     // *             this constant is for units cm,gev/c and kgauss
908     // *
909     Int_t iter = 0;
910     Int_t ncut = 0;
911     for(Int_t j = 0; j < 7; j++)
912       vout[j] = vect[j];
913
914     Double_t  pinv   = kec * charge / vect[6];
915     Double_t tl = 0.;
916     Double_t h = step;
917     Double_t rest;
918
919  
920     do {
921       rest  = step - tl;
922       if (TMath::Abs(h) > TMath::Abs(rest)) h = rest;
923       //cmodif: call gufld(vout,f) changed into:
924
925       GetField(vout,f);
926
927       // *
928       // *             start of integration
929       // *
930       x      = vout[0];
931       y      = vout[1];
932       z      = vout[2];
933       a      = vout[3];
934       b      = vout[4];
935       c      = vout[5];
936
937       h2     = khalf * h;
938       h4     = khalf * h2;
939       ph     = pinv * h;
940       ph2    = khalf * ph;
941       secxs[0] = (b * f[2] - c * f[1]) * ph2;
942       secys[0] = (c * f[0] - a * f[2]) * ph2;
943       seczs[0] = (a * f[1] - b * f[0]) * ph2;
944       ang2 = (secxs[0]*secxs[0] + secys[0]*secys[0] + seczs[0]*seczs[0]);
945       if (ang2 > kpisqua) break;
946
947       dxt    = h2 * a + h4 * secxs[0];
948       dyt    = h2 * b + h4 * secys[0];
949       dzt    = h2 * c + h4 * seczs[0];
950       xt     = x + dxt;
951       yt     = y + dyt;
952       zt     = z + dzt;
953       // *
954       // *              second intermediate point
955       // *
956
957       est = TMath::Abs(dxt) + TMath::Abs(dyt) + TMath::Abs(dzt);
958       if (est > h) {
959         if (ncut++ > maxcut) break;
960         h *= khalf;
961         continue;
962       }
963  
964       xyzt[0] = xt;
965       xyzt[1] = yt;
966       xyzt[2] = zt;
967
968       //cmodif: call gufld(xyzt,f) changed into:
969       GetField(xyzt,f);
970
971       at     = a + secxs[0];
972       bt     = b + secys[0];
973       ct     = c + seczs[0];
974
975       secxs[1] = (bt * f[2] - ct * f[1]) * ph2;
976       secys[1] = (ct * f[0] - at * f[2]) * ph2;
977       seczs[1] = (at * f[1] - bt * f[0]) * ph2;
978       at     = a + secxs[1];
979       bt     = b + secys[1];
980       ct     = c + seczs[1];
981       secxs[2] = (bt * f[2] - ct * f[1]) * ph2;
982       secys[2] = (ct * f[0] - at * f[2]) * ph2;
983       seczs[2] = (at * f[1] - bt * f[0]) * ph2;
984       dxt    = h * (a + secxs[2]);
985       dyt    = h * (b + secys[2]);
986       dzt    = h * (c + seczs[2]);
987       xt     = x + dxt;
988       yt     = y + dyt;
989       zt     = z + dzt;
990       at     = a + 2.*secxs[2];
991       bt     = b + 2.*secys[2];
992       ct     = c + 2.*seczs[2];
993
994       est = TMath::Abs(dxt)+TMath::Abs(dyt)+TMath::Abs(dzt);
995       if (est > 2.*TMath::Abs(h)) {
996         if (ncut++ > maxcut) break;
997         h *= khalf;
998         continue;
999       }
1000  
1001       xyzt[0] = xt;
1002       xyzt[1] = yt;
1003       xyzt[2] = zt;
1004
1005       //cmodif: call gufld(xyzt,f) changed into:
1006       GetField(xyzt,f);
1007
1008       z      = z + (c + (seczs[0] + seczs[1] + seczs[2]) * kthird) * h;
1009       y      = y + (b + (secys[0] + secys[1] + secys[2]) * kthird) * h;
1010       x      = x + (a + (secxs[0] + secxs[1] + secxs[2]) * kthird) * h;
1011
1012       secxs[3] = (bt*f[2] - ct*f[1])* ph2;
1013       secys[3] = (ct*f[0] - at*f[2])* ph2;
1014       seczs[3] = (at*f[1] - bt*f[0])* ph2;
1015       a      = a+(secxs[0]+secxs[3]+2. * (secxs[1]+secxs[2])) * kthird;
1016       b      = b+(secys[0]+secys[3]+2. * (secys[1]+secys[2])) * kthird;
1017       c      = c+(seczs[0]+seczs[3]+2. * (seczs[1]+seczs[2])) * kthird;
1018
1019       est    = TMath::Abs(secxs[0]+secxs[3] - (secxs[1]+secxs[2]))
1020         + TMath::Abs(secys[0]+secys[3] - (secys[1]+secys[2]))
1021         + TMath::Abs(seczs[0]+seczs[3] - (seczs[1]+seczs[2]));
1022
1023       if (est > kdlt && TMath::Abs(h) > 1.e-4) {
1024         if (ncut++ > maxcut) break;
1025         h *= khalf;
1026         continue;
1027       }
1028
1029       ncut = 0;
1030       // *               if too many iterations, go to helix
1031       if (iter++ > maxit) break;
1032
1033       tl += h;
1034       if (est < kdlt32) 
1035         h *= 2.;
1036       cba    = 1./ TMath::Sqrt(a*a + b*b + c*c);
1037       vout[0] = x;
1038       vout[1] = y;
1039       vout[2] = z;
1040       vout[3] = cba*a;
1041       vout[4] = cba*b;
1042       vout[5] = cba*c;
1043       rest = step - tl;
1044       if (step < 0.) rest = -rest;
1045       if (rest < 1.e-5*TMath::Abs(step)) return;
1046
1047     } while(1);
1048
1049     // angle too big, use helix
1050
1051     f1  = f[0];
1052     f2  = f[1];
1053     f3  = f[2];
1054     f4  = TMath::Sqrt(f1*f1+f2*f2+f3*f3);
1055     rho = -f4*pinv;
1056     tet = rho * step;
1057  
1058     hnorm = 1./f4;
1059     f1 = f1*hnorm;
1060     f2 = f2*hnorm;
1061     f3 = f3*hnorm;
1062
1063     hxp[0] = f2*vect[kipz] - f3*vect[kipy];
1064     hxp[1] = f3*vect[kipx] - f1*vect[kipz];
1065     hxp[2] = f1*vect[kipy] - f2*vect[kipx];
1066  
1067     hp = f1*vect[kipx] + f2*vect[kipy] + f3*vect[kipz];
1068
1069     rho1 = 1./rho;
1070     sint = TMath::Sin(tet);
1071     cost = 2.*TMath::Sin(khalf*tet)*TMath::Sin(khalf*tet);
1072
1073     g1 = sint*rho1;
1074     g2 = cost*rho1;
1075     g3 = (tet-sint) * hp*rho1;
1076     g4 = -cost;
1077     g5 = sint;
1078     g6 = cost * hp;
1079  
1080     vout[kix] = vect[kix] + g1*vect[kipx] + g2*hxp[0] + g3*f1;
1081     vout[kiy] = vect[kiy] + g1*vect[kipy] + g2*hxp[1] + g3*f2;
1082     vout[kiz] = vect[kiz] + g1*vect[kipz] + g2*hxp[2] + g3*f3;
1083  
1084     vout[kipx] = vect[kipx] + g4*vect[kipx] + g5*hxp[0] + g6*f1;
1085     vout[kipy] = vect[kipy] + g4*vect[kipy] + g5*hxp[1] + g6*f2;
1086     vout[kipz] = vect[kipz] + g4*vect[kipz] + g5*hxp[2] + g6*f3;
1087
1088     return;
1089 }
1090 //___________________________________________________________
1091  void  AliMUONTrackExtrap::GetField(Double_t *Position, Double_t *Field)
1092 {
1093   /// interface for arguments in double precision (Why ? ChF)
1094   Float_t x[3], b[3];
1095
1096   x[0] = Position[0]; x[1] = Position[1]; x[2] = Position[2];
1097
1098   if (fgkField) fgkField->Field(x,b);
1099   else {
1100     cout<<"F-AliMUONTrackExtrap::GetField: fgkField = 0x0"<<endl;
1101     exit(-1);
1102   }
1103   
1104   Field[0] = b[0]; Field[1] = b[1]; Field[2] = b[2];
1105
1106   return;
1107 }
1108