]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - MUON/AliMUONTrackExtrap.cxx
- Added new option (AliMUONVTrackReconstructor::fgkComplementTracks) to add
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackExtrap.cxx
index b65a77a6a30fedc05b3dc822b5432e9455875d93..3c38ab3a54256434303a3f79a3f05a3bda18c321 100644 (file)
 
 /* $Id$ */
 
-///////////////////////////////////////////////////
-//
-// Tools
-// for
-// track
-// extrapolation
-// in
-// ALICE
-// dimuon
-// spectrometer
-//
-///////////////////////////////////////////////////
-
-#include <Riostream.h>
+//-----------------------------------------------------------------------------
+// Class AliMUONTrackExtrap
+// ------------------------
+// Tools for track extrapolation in ALICE dimuon spectrometer
+// Author: Philippe Pillot
+//-----------------------------------------------------------------------------
 
 #include "AliMUONTrackExtrap.h" 
 #include "AliMUONTrackParam.h"
 #include "AliMUONConstants.h"
+
 #include "AliMagF.h" 
-#include "AliLog.h" 
-#include "AliTracker.h"
 
+#include <TMath.h>
+#include <TMatrixD.h>
+#include <TGeoManager.h>
+
+#include <Riostream.h>
+
+/// \cond CLASSIMP
 ClassImp(AliMUONTrackExtrap) // Class implementation in ROOT context
+/// \endcond
 
 const AliMagF* AliMUONTrackExtrap::fgkField = 0x0;
+const Bool_t   AliMUONTrackExtrap::fgkUseHelix = kFALSE;
+const Int_t    AliMUONTrackExtrap::fgkMaxStepNumber = 5000;
+const Double_t AliMUONTrackExtrap::fgkHelixStepLength = 6.;
+const Double_t AliMUONTrackExtrap::fgkRungeKuttaMaxResidue = 0.002;
+
+  //__________________________________________________________________________
+Double_t AliMUONTrackExtrap::GetImpactParamFromBendingMomentum(Double_t bendingMomentum)
+{
+  /// Returns impact parameter at vertex in bending plane (cm),
+  /// from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
+  /// using simple values for dipole magnetic field.
+  /// The sign of "BendingMomentum" is the sign of the charge.
+  
+  if (bendingMomentum == 0.) return 1.e10;
+  
+  Double_t simpleBPosition = 0.5 * (AliMUONConstants::CoilZ() + AliMUONConstants::YokeZ());
+  Double_t simpleBLength = 0.5 * (AliMUONConstants::CoilL() + AliMUONConstants::YokeL());
+  Float_t b[3], x[3] = {0.,0.,(Float_t) simpleBPosition};
+  if (fgkField) fgkField->Field(x,b);
+  else {
+    cout<<"F-AliMUONTrackExtrap::GetField: fgkField = 0x0"<<endl;
+    exit(-1);
+  }
+  Double_t simpleBValue = (Double_t) b[0];
+  
+  return (-0.0003 * simpleBValue * simpleBLength * simpleBPosition / bendingMomentum);
+}
+
+  //__________________________________________________________________________
+Double_t AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(Double_t impactParam)
+{
+  /// Returns signed bending momentum in bending plane (GeV/c),
+  /// the sign being the sign of the charge for particles moving forward in Z,
+  /// from the impact parameter "ImpactParam" at vertex in bending plane (cm),
+  /// using simple values for dipole magnetic field.
+  
+  if (impactParam == 0.) return 1.e10;
+  
+  Double_t simpleBPosition = 0.5 * (AliMUONConstants::CoilZ() + AliMUONConstants::YokeZ());
+  Double_t simpleBLength = 0.5 * (AliMUONConstants::CoilL() + AliMUONConstants::YokeL());
+  Float_t b[3], x[3] = {0.,0.,(Float_t) simpleBPosition};
+  if (fgkField) fgkField->Field(x,b);
+  else {
+    cout<<"F-AliMUONTrackExtrap::GetField: fgkField = 0x0"<<endl;
+    exit(-1);
+  }
+  Double_t simpleBValue = (Double_t) b[0];
+  
+  return (-0.0003 * simpleBValue * simpleBLength * simpleBPosition / impactParam);
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::LinearExtrapToZ(AliMUONTrackParam* trackParam, Double_t zEnd)
+{
+  /// Track parameters (and their covariances if any) linearly extrapolated to the plane at "zEnd".
+  /// On return, results from the extrapolation are updated in trackParam.
+  
+  if (trackParam->GetZ() == zEnd) return; // nothing to be done if same z
+  
+  // Compute track parameters
+  Double_t dZ = zEnd - trackParam->GetZ();
+  trackParam->SetNonBendingCoor(trackParam->GetNonBendingCoor() + trackParam->GetNonBendingSlope() * dZ);
+  trackParam->SetBendingCoor(trackParam->GetBendingCoor() + trackParam->GetBendingSlope() * dZ);
+  trackParam->SetZ(zEnd);
+  
+  // Update track parameters covariances if any
+  if (trackParam->CovariancesExist()) {
+    TMatrixD paramCov(trackParam->GetCovariances());
+    paramCov(0,0) += dZ * dZ * paramCov(1,1) + 2. * dZ * paramCov(0,1);
+    paramCov(0,1) += dZ * paramCov(1,1);
+    paramCov(1,0) = paramCov(0,1);
+    paramCov(2,2) += dZ * dZ * paramCov(3,3) + 2. * dZ * paramCov(2,3);
+    paramCov(2,3) += dZ * paramCov(3,3);
+    paramCov(3,2) = paramCov(2,3);
+    trackParam->SetCovariances(paramCov);
+  }
+  
+}
 
   //__________________________________________________________________________
 void AliMUONTrackExtrap::ExtrapToZ(AliMUONTrackParam* trackParam, Double_t zEnd)
 {
-  /// Track parameter extrapolation to the plane at "Z".
+  /// Interface to track parameter extrapolation to the plane at "Z" using Helix or Rungekutta algorithm.
+  /// On return, the track parameters resulting from the extrapolation are updated in trackParam.
+  if (fgkUseHelix) AliMUONTrackExtrap::ExtrapToZHelix(trackParam,zEnd);
+  else AliMUONTrackExtrap::ExtrapToZRungekutta(trackParam,zEnd);
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::ExtrapToZHelix(AliMUONTrackParam* trackParam, Double_t zEnd)
+{
+  /// Track parameter extrapolation to the plane at "Z" using Helix algorithm.
   /// On return, the track parameters resulting from the extrapolation are updated in trackParam.
   if (trackParam->GetZ() == zEnd) return; // nothing to be done if same Z
   Double_t forwardBackward; // +1 if forward, -1 if backward
   if (zEnd < trackParam->GetZ()) forwardBackward = 1.0; // spectro. z<0 
   else forwardBackward = -1.0;
-  Double_t vGeant3[7], vGeant3New[7]; // 7 in parameter ????
-  Int_t iGeant3, stepNumber;
-  Int_t maxStepNumber = 5000; // in parameter ????
+  Double_t v3[7], v3New[7]; // 7 in parameter ????
+  Int_t i3, stepNumber;
   // For safety: return kTRUE or kFALSE ????
   // Parameter vector for calling EXTRAP_ONESTEP
-  SetGeant3ParametersFromTrackParam(trackParam, vGeant3, forwardBackward);
+  ConvertTrackParamForExtrap(trackParam, forwardBackward, v3);
   // sign of charge (sign of fInverseBendingMomentum if forward motion)
   // must be changed if backward extrapolation
-  Double_t chargeExtrap = forwardBackward *
-    TMath::Sign(Double_t(1.0), trackParam->GetInverseBendingMomentum());
-  Double_t stepLength = 6.0; // in parameter ????
+  Double_t chargeExtrap = forwardBackward * TMath::Sign(Double_t(1.0), trackParam->GetInverseBendingMomentum());
   // Extrapolation loop
   stepNumber = 0;
-  while (((-forwardBackward * (vGeant3[2] - zEnd)) <= 0.0) &&  // spectro. z<0
-        (stepNumber < maxStepNumber)) {
+  while (((-forwardBackward * (v3[2] - zEnd)) <= 0.0) && (stepNumber < fgkMaxStepNumber)) { // spectro. z<0
     stepNumber++;
-    // Option for switching between helix and Runge-Kutta ???? 
-    //ExtrapOneStepRungekutta(chargeExtrap, stepLength, vGeant3, vGeant3New);
-    ExtrapOneStepHelix(chargeExtrap, stepLength, vGeant3, vGeant3New);
-    if ((-forwardBackward * (vGeant3New[2] - zEnd)) > 0.0) break; // one is beyond Z spectro. z<0
+    ExtrapOneStepHelix(chargeExtrap, fgkHelixStepLength, v3, v3New);
+    if ((-forwardBackward * (v3New[2] - zEnd)) > 0.0) break; // one is beyond Z spectro. z<0
     // better use TArray ????
-    for (iGeant3 = 0; iGeant3 < 7; iGeant3++)
-      {vGeant3[iGeant3] = vGeant3New[iGeant3];}
+    for (i3 = 0; i3 < 7; i3++) {v3[i3] = v3New[i3];}
   }
-  // check maxStepNumber ????
+  // check fgkMaxStepNumber ????
   // Interpolation back to exact Z (2nd order)
   // should be in function ???? using TArray ????
-  Double_t dZ12 = vGeant3New[2] - vGeant3[2]; // 1->2
+  Double_t dZ12 = v3New[2] - v3[2]; // 1->2
   if (TMath::Abs(dZ12) > 0) {
-    Double_t dZ1i = zEnd - vGeant3[2]; // 1-i
-    Double_t dZi2 = vGeant3New[2] - zEnd; // i->2
-    Double_t xPrime = (vGeant3New[0] - vGeant3[0]) / dZ12;
-    Double_t xSecond = ((vGeant3New[3] / vGeant3New[5]) - (vGeant3[3] / vGeant3[5])) / dZ12;
-    Double_t yPrime = (vGeant3New[1] - vGeant3[1]) / dZ12;
-    Double_t ySecond = ((vGeant3New[4] / vGeant3New[5]) - (vGeant3[4] / vGeant3[5])) / dZ12;
-    vGeant3[0] = vGeant3[0] + xPrime * dZ1i - 0.5 * xSecond * dZ1i * dZi2; // X
-    vGeant3[1] = vGeant3[1] + yPrime * dZ1i - 0.5 * ySecond * dZ1i * dZi2; // Y
-    vGeant3[2] = zEnd; // Z
+    Double_t dZ1i = zEnd - v3[2]; // 1-i
+    Double_t dZi2 = v3New[2] - zEnd; // i->2
+    Double_t xPrime = (v3New[0] - v3[0]) / dZ12;
+    Double_t xSecond = ((v3New[3] / v3New[5]) - (v3[3] / v3[5])) / dZ12;
+    Double_t yPrime = (v3New[1] - v3[1]) / dZ12;
+    Double_t ySecond = ((v3New[4] / v3New[5]) - (v3[4] / v3[5])) / dZ12;
+    v3[0] = v3[0] + xPrime * dZ1i - 0.5 * xSecond * dZ1i * dZi2; // X
+    v3[1] = v3[1] + yPrime * dZ1i - 0.5 * ySecond * dZ1i * dZi2; // Y
+    v3[2] = zEnd; // Z
     Double_t xPrimeI = xPrime - 0.5 * xSecond * (dZi2 - dZ1i);
     Double_t yPrimeI = yPrime - 0.5 * ySecond * (dZi2 - dZ1i);
     // (PX, PY, PZ)/PTOT assuming forward motion
-    vGeant3[5] =
-      1.0 / TMath::Sqrt(1.0 + xPrimeI * xPrimeI + yPrimeI * yPrimeI); // PZ/PTOT
-    vGeant3[3] = xPrimeI * vGeant3[5]; // PX/PTOT
-    vGeant3[4] = yPrimeI * vGeant3[5]; // PY/PTOT
+    v3[5] = 1.0 / TMath::Sqrt(1.0 + xPrimeI * xPrimeI + yPrimeI * yPrimeI); // PZ/PTOT
+    v3[3] = xPrimeI * v3[5]; // PX/PTOT
+    v3[4] = yPrimeI * v3[5]; // PY/PTOT
   } else {
-    cout<<"W-AliMUONTrackExtrap::ExtrapToZ: Extrap. to Z not reached, Z = "<<zEnd<<endl;
+    cout<<"W-AliMUONTrackExtrap::ExtrapToZHelix: Extrap. to Z not reached, Z = "<<zEnd<<endl;
   }
-  // Track parameters from Geant3 parameters,
-  // with charge back for forward motion
-  SetTrackParamFromGeant3Parameters(vGeant3, chargeExtrap * forwardBackward, trackParam);
+  // Recover track parameters (charge back for forward motion)
+  RecoverTrackParam(v3, chargeExtrap * forwardBackward, trackParam);
 }
 
   //__________________________________________________________________________
-void AliMUONTrackExtrap::SetGeant3ParametersFromTrackParam(AliMUONTrackParam* trackParam, Double_t *vGeant3, Double_t forwardBackward)
+void AliMUONTrackExtrap::ExtrapToZRungekutta(AliMUONTrackParam* trackParam, Double_t zEnd)
 {
-  /// Set vector of Geant3 parameters pointed to by "vGeant3" from track parameters in trackParam.
+  /// Track parameter extrapolation to the plane at "Z" using Rungekutta algorithm.
+  /// On return, the track parameters resulting from the extrapolation are updated in trackParam.
+  if (trackParam->GetZ() == zEnd) return; // nothing to be done if same Z
+  Double_t forwardBackward; // +1 if forward, -1 if backward
+  if (zEnd < trackParam->GetZ()) forwardBackward = 1.0; // spectro. z<0 
+  else forwardBackward = -1.0;
+  // sign of charge (sign of fInverseBendingMomentum if forward motion)
+  // must be changed if backward extrapolation
+  Double_t chargeExtrap = forwardBackward * TMath::Sign(Double_t(1.0), trackParam->GetInverseBendingMomentum());
+  Double_t v3[7], v3New[7];
+  Double_t dZ, step;
+  Int_t stepNumber = 0;
+  
+  // Extrapolation loop (until within tolerance)
+  Double_t residue = zEnd - trackParam->GetZ();
+  while (TMath::Abs(residue) > fgkRungeKuttaMaxResidue && stepNumber <= fgkMaxStepNumber) {
+    dZ = zEnd - trackParam->GetZ();
+    // step lenght assuming linear trajectory
+    step = dZ * TMath::Sqrt(1.0 + trackParam->GetBendingSlope()*trackParam->GetBendingSlope() +
+                           trackParam->GetNonBendingSlope()*trackParam->GetNonBendingSlope());
+    ConvertTrackParamForExtrap(trackParam, forwardBackward, v3);
+    do { // reduce step lenght while zEnd oversteped
+      if (stepNumber > fgkMaxStepNumber) {
+        cout<<"W-AliMUONTrackExtrap::ExtrapToZRungekutta: Too many trials: "<<stepNumber<<endl;
+       break;
+      }
+      stepNumber ++;
+      step = TMath::Abs(step);
+      AliMUONTrackExtrap::ExtrapOneStepRungekutta(chargeExtrap,step,v3,v3New);
+      residue = zEnd - v3New[2];
+      step *= dZ/(v3New[2]-trackParam->GetZ());
+    } while (residue*dZ < 0 && TMath::Abs(residue) > fgkRungeKuttaMaxResidue);
+    RecoverTrackParam(v3New, chargeExtrap * forwardBackward, trackParam);
+  }
+  
+  // terminate the extropolation with a straight line up to the exact "zEnd" value
+  trackParam->SetNonBendingCoor(trackParam->GetNonBendingCoor() + residue * trackParam->GetNonBendingSlope());
+  trackParam->SetBendingCoor(trackParam->GetBendingCoor() + residue * trackParam->GetBendingSlope());
+  trackParam->SetZ(zEnd);
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::ConvertTrackParamForExtrap(AliMUONTrackParam* trackParam, Double_t forwardBackward, Double_t *v3)
+{
+  /// Set vector of Geant3 parameters pointed to by "v3" from track parameters in trackParam.
   /// Since AliMUONTrackParam is only geometry, one uses "forwardBackward"
   /// to know whether the particle is going forward (+1) or backward (-1).
-  vGeant3[0] = trackParam->GetNonBendingCoor(); // X
-  vGeant3[1] = trackParam->GetBendingCoor(); // Y
-  vGeant3[2] = trackParam->GetZ(); // Z
+  v3[0] = trackParam->GetNonBendingCoor(); // X
+  v3[1] = trackParam->GetBendingCoor(); // Y
+  v3[2] = trackParam->GetZ(); // Z
   Double_t pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
   Double_t pZ = pYZ / TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope());
-  vGeant3[6] = TMath::Sqrt(pYZ * pYZ + pZ * pZ * trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()); // PTOT
-  vGeant3[5] = -forwardBackward * pZ / vGeant3[6]; // PZ/PTOT spectro. z<0
-  vGeant3[3] = trackParam->GetNonBendingSlope() * vGeant3[5]; // PX/PTOT
-  vGeant3[4] = trackParam->GetBendingSlope() * vGeant3[5]; // PY/PTOT
+  v3[6] = TMath::Sqrt(pYZ * pYZ + pZ * pZ * trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()); // PTOT
+  v3[5] = -forwardBackward * pZ / v3[6]; // PZ/PTOT spectro. z<0
+  v3[3] = trackParam->GetNonBendingSlope() * v3[5]; // PX/PTOT
+  v3[4] = trackParam->GetBendingSlope() * v3[5]; // PY/PTOT
 }
 
   //__________________________________________________________________________
-void AliMUONTrackExtrap::SetTrackParamFromGeant3Parameters(Double_t *vGeant3, Double_t charge, AliMUONTrackParam* trackParam)
+void AliMUONTrackExtrap::RecoverTrackParam(Double_t *v3, Double_t charge, AliMUONTrackParam* trackParam)
 {
-  /// Set track parameters in trackParam from Geant3 parameters pointed to by "vGeant3",
+  /// Set track parameters in trackParam from Geant3 parameters pointed to by "v3",
   /// assumed to be calculated for forward motion in Z.
   /// "InverseBendingMomentum" is signed with "charge".
-  trackParam->SetNonBendingCoor(vGeant3[0]); // X
-  trackParam->SetBendingCoor(vGeant3[1]); // Y
-  trackParam->SetZ(vGeant3[2]); // Z
-  Double_t pYZ = vGeant3[6] * TMath::Sqrt(1.0 - vGeant3[3] * vGeant3[3]);
+  trackParam->SetNonBendingCoor(v3[0]); // X
+  trackParam->SetBendingCoor(v3[1]); // Y
+  trackParam->SetZ(v3[2]); // Z
+  Double_t pYZ = v3[6] * TMath::Sqrt(1.0 - v3[3] * v3[3]);
   trackParam->SetInverseBendingMomentum(charge/pYZ);
-  trackParam->SetBendingSlope(vGeant3[4]/vGeant3[5]);
-  trackParam->SetNonBendingSlope(vGeant3[3]/vGeant3[5]);
+  trackParam->SetBendingSlope(v3[4]/v3[5]);
+  trackParam->SetNonBendingSlope(v3[3]/v3[5]);
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd, Bool_t updatePropagator)
+{
+  /// Track parameters and their covariances extrapolated to the plane at "zEnd".
+  /// On return, results from the extrapolation are updated in trackParam.
+  
+  if (trackParam->GetZ() == zEnd) return; // nothing to be done if same z
+  
+  // No need to propagate the covariance matrix if it does not exist
+  if (!trackParam->CovariancesExist()) {
+    cout<<"W-AliMUONTrackExtrap::ExtrapToZCov: Covariance matrix does not exist"<<endl;
+    // Extrapolate track parameters to "zEnd"
+    ExtrapToZ(trackParam,zEnd);
+    return;
+  }
+  
+  // Save the actual track parameters
+  AliMUONTrackParam trackParamSave(*trackParam);
+  TMatrixD paramSave(trackParamSave.GetParameters());
+  Double_t zBegin = trackParamSave.GetZ();
+  
+  // Get reference to the parameter covariance matrix
+  const TMatrixD& kParamCov = trackParam->GetCovariances();
+  
+  // Extrapolate track parameters to "zEnd"
+  ExtrapToZ(trackParam,zEnd);
+  
+  // Get reference to the extrapolated parameters
+  const TMatrixD& extrapParam = trackParam->GetParameters();
+  
+  // Calculate the jacobian related to the track parameters extrapolation to "zEnd"
+  TMatrixD jacob(5,5);
+  jacob.Zero();
+  TMatrixD dParam(5,1);
+  for (Int_t i=0; i<5; i++) {
+    // Skip jacobian calculation for parameters with no associated error
+    if (kParamCov(i,i) == 0.) continue;
+    
+    // Small variation of parameter i only
+    for (Int_t j=0; j<5; j++) {
+      if (j==i) {
+        dParam(j,0) = TMath::Sqrt(kParamCov(i,i));
+       if (j == 4) dParam(j,0) *= TMath::Sign(1.,-paramSave(4,0)); // variation always in the same direction
+      } else dParam(j,0) = 0.;
+    }
+    
+    // Set new parameters
+    trackParamSave.SetParameters(paramSave);
+    trackParamSave.AddParameters(dParam);
+    trackParamSave.SetZ(zBegin);
+    
+    // Extrapolate new track parameters to "zEnd"
+    ExtrapToZ(&trackParamSave,zEnd);
+    
+    // Calculate the jacobian
+    TMatrixD jacobji(trackParamSave.GetParameters(),TMatrixD::kMinus,extrapParam);
+    jacobji *= 1. / dParam(i,0);
+    jacob.SetSub(0,i,jacobji);
+  }
+  
+  // Extrapolate track parameter covariances to "zEnd"
+  TMatrixD tmp(kParamCov,TMatrixD::kMultTranspose,jacob);
+  TMatrixD tmp2(jacob,TMatrixD::kMult,tmp);
+  trackParam->SetCovariances(tmp2);
+  
+  // Update the propagator if required
+  if (updatePropagator) trackParam->UpdatePropagator(jacob);
+  
 }
 
   //__________________________________________________________________________
@@ -150,7 +341,7 @@ void AliMUONTrackExtrap::ExtrapToStation(AliMUONTrackParam* trackParamIn, Int_t
   if ((z1 > trackParamIn->GetZ()) && (z2 > trackParamIn->GetZ())) {i1 = 0; i2 = 1;}
   else if ((z1 < trackParamIn->GetZ()) && (z2 < trackParamIn->GetZ())) {i1 = 1; i2 = 0;}
   else {
-    cout<<"E-AliMUONTrackExtrap::ExtrapToStationAliError: Starting Z ("<<trackParamIn->GetZ()
+    cout<<"E-AliMUONTrackExtrap::ExtrapToStation: Starting Z ("<<trackParamIn->GetZ()
        <<") in between z1 ("<<z1<<") and z2 ("<<z2<<") of station(0..)"<<station<<endl;
     exit(-1);
   }
@@ -167,288 +358,433 @@ void AliMUONTrackExtrap::ExtrapToStation(AliMUONTrackParam* trackParamIn, Int_t
 }
 
   //__________________________________________________________________________
-void AliMUONTrackExtrap::ExtrapToVertex(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx)
+void AliMUONTrackExtrap::ExtrapToVertexUncorrected(AliMUONTrackParam* trackParam, Double_t zVtx)
 {
-  /// Extrapolation to the vertex.
+  /// Extrapolation to the vertex (at the z position "zVtx") without Branson and energy loss corrections.
   /// Returns the track parameters resulting from the extrapolation in the current TrackParam.
-  /// Changes parameters according to Branson correction through the absorber 
-  
-  Double_t zAbsorber = -503.0; // to be coherent with the Geant absorber geometry !!!!
-                               // spectro. (z<0) 
-  // Extrapolates track parameters upstream to the "Z" end of the front absorber
-  ExtrapToZ(trackParam,zAbsorber); // !!!
-  // Makes Branson correction (multiple scattering + energy loss)
-  BransonCorrection(trackParam,xVtx,yVtx,zVtx);
-  // Makes a simple magnetic field correction through the absorber
-  FieldCorrection(trackParam,zAbsorber);
+  /// Include multiple Coulomb scattering effects in trackParam covariances.
+  
+  if (trackParam->GetZ() == zVtx) return; // nothing to be done if already at vertex
+  
+  if (trackParam->GetZ() > zVtx) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertexUncorrected: Starting Z ("<<trackParam->GetZ()
+       <<") upstream the vertex (zVtx = "<<zVtx<<")"<<endl;
+    exit(-1);
+  }
+  
+  // Check the vertex position relatively to the absorber
+  if (zVtx < AliMUONConstants::AbsZBeg() && zVtx > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+  } else if (zVtx < AliMUONConstants::AbsZEnd() ) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
+       <<") downstream the front absorber (zAbsorberEnd = "<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,zVtx);
+    else ExtrapToZ(trackParam,zVtx);
+    return;
+  }
+  
+  // Check the track position relatively to the absorber and extrapolate track parameters to the end of the absorber if needed
+  if (trackParam->GetZ() > AliMUONConstants::AbsZBeg()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
+       <<") upstream the front absorber (zAbsorberBegin = "<<AliMUONConstants::AbsZBeg()<<")"<<endl;
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,zVtx);
+    else ExtrapToZ(trackParam,zVtx);
+    return;
+  } else if (trackParam->GetZ() > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+  } else {
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,AliMUONConstants::AbsZEnd());
+    else ExtrapToZ(trackParam,AliMUONConstants::AbsZEnd());
+  }
+  
+  // Then add MCS effect in absorber to the parameters covariances
+  AliMUONTrackParam trackParamIn(*trackParam);
+  ExtrapToZ(&trackParamIn, TMath::Min(zVtx, AliMUONConstants::AbsZBeg()));
+  Double_t trackXYZIn[3];
+  trackXYZIn[0] = trackParamIn.GetNonBendingCoor();
+  trackXYZIn[1] = trackParamIn.GetBendingCoor();
+  trackXYZIn[2] = trackParamIn.GetZ();
+  Double_t trackXYZOut[3];
+  trackXYZOut[0] = trackParam->GetNonBendingCoor();
+  trackXYZOut[1] = trackParam->GetBendingCoor();
+  trackXYZOut[2] = trackParam->GetZ();
+  Double_t pathLength = 0.;
+  Double_t f0 = 0.;
+  Double_t f1 = 0.;
+  Double_t f2 = 0.;
+  Double_t meanRho = 0.;
+  Double_t totalELoss = 0.;
+  GetAbsorberCorrectionParam(trackXYZIn,trackXYZOut,trackParam->P(),pathLength,f0,f1,f2,meanRho,totalELoss);
+  AddMCSEffectInAbsorber(trackParam,pathLength,f0,f1,f2);
+  
+  // finally go to the vertex
+  ExtrapToZCov(trackParam,zVtx);
+  
 }
 
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::AddMCSEffectInAbsorber(AliMUONTrackParam* param, Double_t pathLength, Double_t f0, Double_t f1, Double_t f2)
+{
+  /// Add to the track parameter covariances the effects of multiple Coulomb scattering
+  /// at the end of the front absorber using the absorber correction parameters
+  
+  // absorber related covariance parameters
+  Double_t bendingSlope = param->GetBendingSlope();
+  Double_t nonBendingSlope = param->GetNonBendingSlope();
+  Double_t inverseBendingMomentum = param->GetInverseBendingMomentum();
+  Double_t alpha2 = 0.0136 * 0.0136 * inverseBendingMomentum * inverseBendingMomentum * (1.0 + bendingSlope * bendingSlope) /
+                                       (1.0 + bendingSlope *bendingSlope + nonBendingSlope * nonBendingSlope); // velocity = 1
+  Double_t varCoor = alpha2 * (pathLength * pathLength * f0 - 2. * pathLength * f1 + f2);
+  Double_t covCorrSlope = alpha2 * (pathLength * f0 - f1);
+  Double_t varSlop = alpha2 * f0;
+  
+  TMatrixD newParamCov(param->GetCovariances());
+  // Non bending plane
+  newParamCov(0,0) += varCoor;       newParamCov(0,1) += covCorrSlope;
+  newParamCov(1,0) += covCorrSlope;  newParamCov(1,1) += varSlop;
+  // Bending plane
+  newParamCov(2,2) += varCoor;       newParamCov(2,3) += covCorrSlope;
+  newParamCov(3,2) += covCorrSlope;  newParamCov(3,3) += varSlop;
+  
+  // Set new covariances
+  param->SetCovariances(newParamCov);
+  
+}
 
-//  Keep this version for future developments
   //__________________________________________________________________________
-// void AliMUONTrackExtrap::BransonCorrection(AliMUONTrackParam* trackParam)
-// {
-//   /// Branson correction of track parameters
-//   // the entry parameters have to be calculated at the end of the absorber
-//   Double_t zEndAbsorber, zBP, xBP, yBP;
-//   Double_t  pYZ, pX, pY, pZ, pTotal, xEndAbsorber, yEndAbsorber, radiusEndAbsorber2, pT, theta;
-//   Int_t sign;
-//   // Would it be possible to calculate all that from Geant configuration ????
-//   // and to get the Branson parameters from a function in ABSO module ????
-//   // with an eventual contribution from other detectors like START ????
-//   // Radiation lengths outer part theta > 3 degres
-//   static Double_t x01[9] = { 18.8,    // C (cm)
-//                          10.397,   // Concrete (cm)
-//                          0.56,    // Plomb (cm)
-//                          47.26,   // Polyethylene (cm)
-//                          0.56,   // Plomb (cm)
-//                          47.26,   // Polyethylene (cm)
-//                          0.56,   // Plomb (cm)
-//                          47.26,   // Polyethylene (cm)
-//                          0.56 };   // Plomb (cm)
-//   // inner part theta < 3 degres
-//   static Double_t x02[3] = { 18.8,    // C (cm)
-//                          10.397,   // Concrete (cm)
-//                          0.35 };    // W (cm) 
-//   // z positions of the materials inside the absober outer part theta > 3 degres
-//   static Double_t z1[10] = { 90, 315, 467, 472, 477, 482, 487, 492, 497, 502 };
-//   // inner part theta < 3 degres
-//   static Double_t z2[4] = { 90, 315, 467, 503 };
-//   static Bool_t first = kTRUE;
-//   static Double_t zBP1, zBP2, rLimit;
-//   // Calculates z positions of the Branson's planes: zBP1 for outer part and zBP2 for inner part (only at the first call)
-//   if (first) {
-//     first = kFALSE;
-//     Double_t aNBP = 0.0;
-//     Double_t aDBP = 0.0;
-//     Int_t iBound;
-//     
-//     for (iBound = 0; iBound < 9; iBound++) {
-//       aNBP = aNBP +
-//     (z1[iBound+1] * z1[iBound+1] * z1[iBound+1] -
-//      z1[iBound]   * z1[iBound]   * z1[iBound]    ) / x01[iBound];
-//       aDBP = aDBP +
-//     (z1[iBound+1] * z1[iBound+1] - z1[iBound]   * z1[iBound]    ) / x01[iBound];
-//     }
-//     zBP1 = (2.0 * aNBP) / (3.0 * aDBP);
-//     aNBP = 0.0;
-//     aDBP = 0.0;
-//     for (iBound = 0; iBound < 3; iBound++) {
-//       aNBP = aNBP +
-//     (z2[iBound+1] * z2[iBound+1] * z2[iBound+1] -
-//      z2[iBound]   * z2[iBound ]  * z2[iBound]    ) / x02[iBound];
-//       aDBP = aDBP +
-//     (z2[iBound+1] * z2[iBound+1] - z2[iBound] * z2[iBound]) / x02[iBound];
-//     }
-//     zBP2 = (2.0 * aNBP) / (3.0 * aDBP);
-//     rLimit = z2[3] * TMath::Tan(3.0 * (TMath::Pi()) / 180.);
-//   }
-// 
-//   pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
-//   sign = 1;      
-//   if (trackParam->GetInverseBendingMomentum() < 0) sign = -1;     
-//   pZ = pYZ / (TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope())); 
-//   pX = pZ * trackParam->GetNonBendingSlope(); 
-//   pY = pZ * trackParam->GetBendingSlope(); 
-//   pTotal = TMath::Sqrt(pYZ *pYZ + pX * pX);
-//   xEndAbsorber = trackParam->GetNonBendingCoor(); 
-//   yEndAbsorber = trackParam->GetBendingCoor(); 
-//   radiusEndAbsorber2 = xEndAbsorber * xEndAbsorber + yEndAbsorber * yEndAbsorber;
-// 
-//   if (radiusEndAbsorber2 > rLimit*rLimit) {
-//     zEndAbsorber = z1[9];
-//     zBP = zBP1;
-//   } else {
-//     zEndAbsorber = z2[3];
-//     zBP = zBP2;
-//   }
-// 
-//   xBP = xEndAbsorber - (pX / pZ) * (zEndAbsorber - zBP);
-//   yBP = yEndAbsorber - (pY / pZ) * (zEndAbsorber - zBP);
-// 
-//   // new parameters after Branson and energy loss corrections
-//   pZ = pTotal * zBP / TMath::Sqrt(xBP * xBP + yBP * yBP + zBP * zBP);
-//   pX = pZ * xBP / zBP;
-//   pY = pZ * yBP / zBP;
-//   trackParam->SetBendingSlope(pY/pZ);
-//   trackParam->SetNonBendingSlope(pX/pZ);
-//   
-//   pT = TMath::Sqrt(pX * pX + pY * pY);      
-//   theta = TMath::ATan2(pT, pZ); 
-//   pTotal = TotalMomentumEnergyLoss(rLimit, pTotal, theta, xEndAbsorber, yEndAbsorber);
-// 
-//   trackParam->SetInverseBendingMomentum((sign / pTotal) *
-//     TMath::Sqrt(1.0 +
-//             trackParam->GetBendingSlope() * trackParam->GetBendingSlope() +
-//             trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()) /
-//     TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope()));
-// 
-//   // vertex position at (0,0,0)
-//   // should be taken from vertex measurement ???
-//   trackParam->SetBendingCoor(0.);
-//   trackParam->SetNonBendingCoor(0.);
-//   trackParam->SetZ(0.);
-// }
-
-void AliMUONTrackExtrap::BransonCorrection(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx)
+void AliMUONTrackExtrap::GetAbsorberCorrectionParam(Double_t trackXYZIn[3], Double_t trackXYZOut[3], Double_t pTotal, Double_t &pathLength,
+                                                   Double_t &f0, Double_t &f1, Double_t &f2, Double_t &meanRho, Double_t &totalELoss)
 {
-  /// Branson correction of track parameters
-  // the entry parameters have to be calculated at the end of the absorber
-  // simplified version: the z positions of Branson's planes are no longer calculated
-  // but are given as inputs. One can use the macros MUONTestAbso.C and DrawTestAbso.C
-  // to test this correction. 
-  // Would it be possible to calculate all that from Geant configuration ????
-  // and to get the Branson parameters from a function in ABSO module ????
-  // with an eventual contribution from other detectors like START ????
-  // change to take into account the vertex postition (real, reconstruct,....)
-
-  Double_t  zBP, xBP, yBP;
-  Double_t  pYZ, pX, pY, pZ, pTotal, xEndAbsorber, yEndAbsorber, radiusEndAbsorber2, pT, theta;
-  Int_t sign;
-  static Bool_t first = kTRUE;
-  static Double_t zBP1, zBP2, rLimit, thetaLimit, zEndAbsorber;
-  // zBP1 for outer part and zBP2 for inner part (only at the first call)
-  if (first) {
-    first = kFALSE;
-  
-    zEndAbsorber = -503;  // spectro (z<0)
-    thetaLimit = 3.0 * (TMath::Pi()) / 180.;
-    rLimit = TMath::Abs(zEndAbsorber) * TMath::Tan(thetaLimit);
-    zBP1 = -450; // values close to those calculated with EvalAbso.C
-    zBP2 = -480;
+  /// Parameters used to correct for Multiple Coulomb Scattering and energy loss in absorber
+  /// Calculated assuming a linear propagation between track positions trackXYZIn and trackXYZOut
+  // pathLength: path length between trackXYZIn and trackXYZOut (cm)
+  // f0:         0th moment of z calculated with the inverse radiation-length distribution
+  // f1:         1st moment of z calculated with the inverse radiation-length distribution
+  // f2:         2nd moment of z calculated with the inverse radiation-length distribution
+  // meanRho:    average density of crossed material (g/cm3)
+  // totalELoss: total energy loss in absorber
+  
+  // Reset absorber's parameters
+  pathLength = 0.;
+  f0 = 0.;
+  f1 = 0.;
+  f2 = 0.;
+  meanRho = 0.;
+  totalELoss = 0.;
+  
+  // Check whether the geometry is available
+  if (!gGeoManager) {
+    cout<<"E-AliMUONTrackExtrap::GetAbsorberCorrectionParam: no TGeo"<<endl;
+    return;
   }
-
-  pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
-  sign = 1;      
-  if (trackParam->GetInverseBendingMomentum() < 0) sign = -1;  
-  pZ = trackParam->Pz();
-  pX = trackParam->Px(); 
-  pY = trackParam->Py(); 
-  pTotal = TMath::Sqrt(pYZ *pYZ + pX * pX);
-  xEndAbsorber = trackParam->GetNonBendingCoor(); 
-  yEndAbsorber = trackParam->GetBendingCoor(); 
-  radiusEndAbsorber2 = xEndAbsorber * xEndAbsorber + yEndAbsorber * yEndAbsorber;
-
-  if (radiusEndAbsorber2 > rLimit*rLimit) {
-    zBP = zBP1;
-  } else {
-    zBP = zBP2;
+  
+  // Initialize starting point and direction
+  pathLength = TMath::Sqrt((trackXYZOut[0] - trackXYZIn[0])*(trackXYZOut[0] - trackXYZIn[0])+
+                          (trackXYZOut[1] - trackXYZIn[1])*(trackXYZOut[1] - trackXYZIn[1])+
+                          (trackXYZOut[2] - trackXYZIn[2])*(trackXYZOut[2] - trackXYZIn[2]));
+  if (pathLength < TGeoShape::Tolerance()) return;
+  Double_t b[3];
+  b[0] = (trackXYZOut[0] - trackXYZIn[0]) / pathLength;
+  b[1] = (trackXYZOut[1] - trackXYZIn[1]) / pathLength;
+  b[2] = (trackXYZOut[2] - trackXYZIn[2]) / pathLength;
+  TGeoNode *currentnode = gGeoManager->InitTrack(trackXYZIn, b);
+  if (!currentnode) {
+    cout<<"E-AliMUONTrackExtrap::GetAbsorberCorrectionParam: start point out of geometry"<<endl;
+    return;
   }
-
-  xBP = xEndAbsorber - (pX / pZ) * (zEndAbsorber - zBP);
-  yBP = yEndAbsorber - (pY / pZ) * (zEndAbsorber - zBP);
-
-  // new parameters after Branson and energy loss corrections
-//   Float_t zSmear = zBP - gRandom->Gaus(0.,2.);  // !!! possible smearing of Z vertex position
-
-  Float_t zSmear = zBP ;
   
-  pZ = pTotal * (zSmear-zVtx) / TMath::Sqrt((xBP-xVtx) * (xBP-xVtx) + (yBP-yVtx) * (yBP-yVtx) +( zSmear-zVtx) * (zSmear-zVtx) );
-  pX = pZ * (xBP - xVtx)/ (zSmear-zVtx);
-  pY = pZ * (yBP - yVtx) / (zSmear-zVtx);
-  trackParam->SetBendingSlope(pY/pZ);
-  trackParam->SetNonBendingSlope(pX/pZ);
-
+  // loop over absorber slices and calculate absorber's parameters
+  Double_t rho = 0.; // material density (g/cm3)
+  Double_t x0 = 0.;  // radiation-length (cm-1)
+  Double_t atomicA = 0.; // A of material
+  Double_t atomicZ = 0.; // Z of material
+  Double_t localPathLength = 0;
+  Double_t remainingPathLength = pathLength;
+  Double_t zB = trackXYZIn[2];
+  Double_t zE, dzB, dzE;
+  do {
+    // Get material properties
+    TGeoMaterial *material = currentnode->GetVolume()->GetMedium()->GetMaterial();
+    rho = material->GetDensity();
+    x0 = material->GetRadLen();
+    if (!material->IsMixture()) x0 /= rho; // different normalization in the modeler for mixture
+    atomicA = material->GetA();
+    atomicZ = material->GetZ();
+    
+    // Get path length within this material
+    gGeoManager->FindNextBoundary(remainingPathLength);
+    localPathLength = gGeoManager->GetStep() + 1.e-6;
+    // Check if boundary within remaining path length. If so, make sure to cross the boundary to prepare the next step
+    if (localPathLength >= remainingPathLength) localPathLength = remainingPathLength;
+    else {
+      currentnode = gGeoManager->Step();
+      if (!currentnode) {
+        cout<<"E-AliMUONTrackExtrap::GetAbsorberCorrectionParam: navigation failed"<<endl;
+       f0 = f1 = f2 = meanRho = 0.;
+       return;
+      }
+      if (!gGeoManager->IsEntering()) {
+        // make another small step to try to enter in new absorber slice
+        gGeoManager->SetStep(0.001);
+       currentnode = gGeoManager->Step();
+       if (!gGeoManager->IsEntering() || !currentnode) {
+          cout<<"E-AliMUONTrackExtrap::GetAbsorberCorrectionParam: navigation failed"<<endl;
+         f0 = f1 = f2 = meanRho = 0.;
+         return;
+       }
+        localPathLength += 0.001;
+      }
+    }
+    
+    // calculate absorber's parameters
+    zE = b[2] * localPathLength + zB;
+    dzB = zB - trackXYZIn[2];
+    dzE = zE - trackXYZIn[2];
+    f0 += localPathLength / x0;
+    f1 += (dzE*dzE - dzB*dzB) / b[2] / b[2] / x0 / 2.;
+    f2 += (dzE*dzE*dzE - dzB*dzB*dzB) / b[2] / b[2] / b[2] / x0 / 3.;
+    meanRho += localPathLength * rho;
+    totalELoss += BetheBloch(pTotal, localPathLength, rho, atomicA, atomicZ);
+    
+    // prepare next step
+    zB = zE;
+    remainingPathLength -= localPathLength;
+  } while (remainingPathLength > TGeoShape::Tolerance());
   
-  pT = TMath::Sqrt(pX * pX + pY * pY);      
-  theta = TMath::ATan2(pT, TMath::Abs(pZ)); 
-  pTotal = TotalMomentumEnergyLoss(thetaLimit, pTotal, theta);
-
-  trackParam->SetInverseBendingMomentum((sign / pTotal) *
-    TMath::Sqrt(1.0 +
-               trackParam->GetBendingSlope() * trackParam->GetBendingSlope() +
-               trackParam->GetNonBendingSlope() * trackParam->GetNonBendingSlope()) /
-    TMath::Sqrt(1.0 + trackParam->GetBendingSlope() * trackParam->GetBendingSlope()));
-
-  // vertex position at (0,0,0)
-  // should be taken from vertex measurement ???
+  meanRho /= pathLength;
+}
 
-  trackParam->SetBendingCoor(xVtx);
-  trackParam->SetNonBendingCoor(yVtx);
-  trackParam->SetZ(zVtx);
+  //__________________________________________________________________________
+Double_t AliMUONTrackExtrap::GetMCSAngle2(const AliMUONTrackParam& param, Double_t dZ, Double_t x0)
+{
+  /// Return the angular dispersion square due to multiple Coulomb scattering
+  /// through a material of thickness "dZ" and of radiation length "x0"
+  /// assuming linear propagation and using the small angle approximation.
+  
+  Double_t bendingSlope = param.GetBendingSlope();
+  Double_t nonBendingSlope = param.GetNonBendingSlope();
+  Double_t inverseTotalMomentum2 = param.GetInverseBendingMomentum() * param.GetInverseBendingMomentum() *
+                                  (1.0 + bendingSlope * bendingSlope) /
+                                  (1.0 + bendingSlope *bendingSlope + nonBendingSlope * nonBendingSlope); 
+  // Path length in the material
+  Double_t pathLength = TMath::Abs(dZ) * TMath::Sqrt(1.0 + bendingSlope*bendingSlope + nonBendingSlope*nonBendingSlope);
+  // relativistic velocity
+  Double_t velo = 1.;
+  // Angular dispersion square of the track (variance) in a plane perpendicular to the trajectory
+  Double_t theta02 = 0.0136 / velo * (1 + 0.038 * TMath::Log(pathLength/x0));
+  
+  return theta02 * theta02 * inverseTotalMomentum2 * pathLength / x0;
+}
 
+  //__________________________________________________________________________
+void AliMUONTrackExtrap::AddMCSEffect(AliMUONTrackParam *param, Double_t dZ, Double_t x0)
+{
+  /// Add to the track parameter covariances the effects of multiple Coulomb scattering
+  /// through a material of thickness "dZ" and of radiation length "x0"
+  /// assuming linear propagation and using the small angle approximation.
+  
+  Double_t bendingSlope = param->GetBendingSlope();
+  Double_t nonBendingSlope = param->GetNonBendingSlope();
+  Double_t inverseTotalMomentum2 = param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum() *
+                                  (1.0 + bendingSlope * bendingSlope) /
+                                  (1.0 + bendingSlope *bendingSlope + nonBendingSlope * nonBendingSlope); 
+  // Path length in the material
+  Double_t pathLength = TMath::Abs(dZ) * TMath::Sqrt(1.0 + bendingSlope*bendingSlope + nonBendingSlope*nonBendingSlope);
+  Double_t pathLength2 = pathLength * pathLength;
+  // relativistic velocity
+  Double_t velo = 1.;
+  // Angular dispersion square of the track (variance) in a plane perpendicular to the trajectory
+  Double_t theta02 = 0.0136 / velo * (1 + 0.038 * TMath::Log(pathLength/x0));
+  theta02 *= theta02 * inverseTotalMomentum2 * pathLength / x0;
+  
+  Double_t varCoor     = pathLength2 * theta02 / 3.;
+  Double_t varSlop     = theta02;
+  Double_t covCorrSlope = pathLength * theta02 / 2.;
+  
+  // Add effects of multiple Coulomb scattering in track parameter covariances
+  TMatrixD newParamCov(param->GetCovariances());
+  // Non bending plane
+  newParamCov(0,0) += varCoor;       newParamCov(0,1) += covCorrSlope;
+  newParamCov(1,0) += covCorrSlope;  newParamCov(1,1) += varSlop;
+  // Bending plane
+  newParamCov(2,2) += varCoor;       newParamCov(2,3) += covCorrSlope;
+  newParamCov(3,2) += covCorrSlope;  newParamCov(3,3) += varSlop;
+  
+  // Set new covariances
+  param->SetCovariances(newParamCov);
 }
 
   //__________________________________________________________________________
-Double_t AliMUONTrackExtrap::TotalMomentumEnergyLoss(Double_t thetaLimit, Double_t pTotal, Double_t theta)
+void AliMUONTrackExtrap::ExtrapToVertex(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx,
+                                       Bool_t CorrectForMCS, Bool_t CorrectForEnergyLoss)
 {
-  /// Returns the total momentum corrected from energy loss in the front absorber
-  // One can use the macros MUONTestAbso.C and DrawTestAbso.C
-  // to test this correction. 
-  // Momentum energy loss behaviour evaluated with the simulation of single muons (april 2002)
-  Double_t deltaP, pTotalCorrected;
-
-   // Parametrization to be redone according to change of absorber material ????
-  // See remark in function BransonCorrection !!!!
-  // The name is not so good, and there are many arguments !!!!
-  if (theta  < thetaLimit ) {
-    if (pTotal < 20) {
-      deltaP = 2.5938 + 0.0570 * pTotal - 0.001151 * pTotal * pTotal;
-    } else {
-      deltaP = 3.0714 + 0.011767 *pTotal;
-    }
-    deltaP *= 0.75; // AZ
+  /// Extrapolation to the vertex.
+  /// Returns the track parameters resulting from the extrapolation of the current TrackParam.
+  /// Changes parameters according to Branson correction through the absorber and energy loss
+  
+  if (trackParam->GetZ() == zVtx) return; // nothing to be done if already at vertex
+  
+  if (trackParam->GetZ() > zVtx) { // spectro. (z<0)
+    cout<<"F-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
+       <<") upstream the vertex (zVtx = "<<zVtx<<")"<<endl;
+    exit(-1);
+  }
+  
+  // Check if correction required
+  if (!CorrectForMCS && !CorrectForEnergyLoss) {
+    ExtrapToZ(trackParam,zVtx);
+    return;
+  }
+  
+  // Check the vertex position relatively to the absorber
+  if (zVtx < AliMUONConstants::AbsZBeg() && zVtx > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+  } else if (zVtx < AliMUONConstants::AbsZEnd() ) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
+       <<") downstream the front absorber (zAbsorberEnd = "<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+    ExtrapToZ(trackParam,zVtx);
+    return;
+  }
+  
+  // Check the track position relatively to the absorber and extrapolate track parameters to the end of the absorber if needed
+  if (trackParam->GetZ() > AliMUONConstants::AbsZBeg()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
+       <<") upstream the front absorber (zAbsorberBegin = "<<AliMUONConstants::AbsZBeg()<<")"<<endl;
+    ExtrapToZ(trackParam,zVtx);
+    return;
+  } else if (trackParam->GetZ() > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
+    cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
   } else {
-    if (pTotal < 20) {
-      deltaP  = 2.1207 + 0.05478 * pTotal - 0.00145079 * pTotal * pTotal;
-    } else { 
-      deltaP = 2.6069 + 0.0051705 * pTotal;
-    }
-    deltaP *= 0.9; // AZ
+    ExtrapToZ(trackParam,AliMUONConstants::AbsZEnd());
+  }
+  
+  // Get absorber correction parameters assuming linear propagation from vertex to the track position
+  Double_t trackXYZOut[3];
+  trackXYZOut[0] = trackParam->GetNonBendingCoor();
+  trackXYZOut[1] = trackParam->GetBendingCoor();
+  trackXYZOut[2] = trackParam->GetZ();
+  Double_t trackXYZIn[3];
+  trackXYZIn[2] = TMath::Min(zVtx, AliMUONConstants::AbsZBeg()); // spectro. (z<0)
+  trackXYZIn[0] = trackXYZOut[0] + (xVtx - trackXYZOut[0]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]);
+  trackXYZIn[1] = trackXYZOut[1] + (yVtx - trackXYZOut[1]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]);
+  Double_t pTot = trackParam->P();
+  Double_t pathLength = 0.;
+  Double_t f0 = 0.;
+  Double_t f1 = 0.;
+  Double_t f2 = 0.;
+  Double_t meanRho = 0.;
+  Double_t deltaP = 0.;
+  GetAbsorberCorrectionParam(trackXYZIn,trackXYZOut,pTot,pathLength,f0,f1,f2,meanRho,deltaP);
+  
+  // Correct for half of energy loss
+  Double_t nonBendingSlope, bendingSlope;
+  Double_t charge = TMath::Sign(Double_t(1.0), trackParam->GetInverseBendingMomentum());      
+  if (CorrectForEnergyLoss) {
+    pTot += 0.5 * deltaP;
+    nonBendingSlope = trackParam->GetNonBendingSlope();
+    bendingSlope = trackParam->GetBendingSlope();
+    trackParam->SetInverseBendingMomentum(charge / pTot *
+         TMath::Sqrt(1.0 + nonBendingSlope*nonBendingSlope + bendingSlope*bendingSlope) /
+         TMath::Sqrt(1.0 + bendingSlope*bendingSlope));
+  }
+  
+  if (CorrectForMCS) {
+    // Position of the Branson plane (spectro. (z<0))
+    Double_t zB = (f1>0.) ? trackXYZIn[2] - f2/f1 : 0.;
+    
+    // Get track position in the Branson plane corrected for magnetic field effect
+    ExtrapToZ(trackParam,zVtx);
+    Double_t xB = trackParam->GetNonBendingCoor() + (zB - zVtx) * trackParam->GetNonBendingSlope();
+    Double_t yB = trackParam->GetBendingCoor()    + (zB - zVtx) * trackParam->GetBendingSlope();
+    
+    // Get track slopes corrected for multiple scattering (spectro. (z<0))
+    nonBendingSlope = (zB<0.) ? (xB - xVtx) / (zB - zVtx) : trackParam->GetNonBendingSlope();
+    bendingSlope    = (zB<0.) ? (yB - yVtx) / (zB - zVtx) : trackParam->GetBendingSlope();
+    
+    // Set track parameters at vertex
+    trackParam->SetNonBendingCoor(xVtx);
+    trackParam->SetBendingCoor(yVtx);
+    trackParam->SetZ(zVtx);
+    trackParam->SetNonBendingSlope(nonBendingSlope);
+    trackParam->SetBendingSlope(bendingSlope);
+  } else {
+    ExtrapToZ(trackParam,zVtx);
+    nonBendingSlope = trackParam->GetNonBendingSlope();
+    bendingSlope = trackParam->GetBendingSlope();
   }
-  pTotalCorrected = pTotal + deltaP / TMath::Cos(theta);
-  return pTotalCorrected;
+  
+  // Correct for second half of energy loss
+  if (CorrectForEnergyLoss) pTot += 0.5 * deltaP;
+  
+  // Set track parameters at vertex
+  trackParam->SetInverseBendingMomentum(charge / pTot *
+        TMath::Sqrt(1.0 + nonBendingSlope*nonBendingSlope + bendingSlope*bendingSlope) /
+        TMath::Sqrt(1.0 + bendingSlope*bendingSlope));
+  
 }
 
   //__________________________________________________________________________
-void AliMUONTrackExtrap::FieldCorrection(AliMUONTrackParam *trackParam, Double_t zEnd)
+Double_t AliMUONTrackExtrap::TotalMomentumEnergyLoss(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx)
 {
-  /// Correction of the effect of the magnetic field in the absorber
-  // Assume a constant field along Z axis.
-  Float_t b[3],x[3]; 
-  Double_t bZ;
-  Double_t pYZ,pX,pY,pZ,pT;
-  Double_t pXNew,pYNew;
-  Double_t c;
-
-  pYZ = TMath::Abs(1.0 / trackParam->GetInverseBendingMomentum());
-  c = TMath::Sign(1.0,trackParam->GetInverseBendingMomentum()); // particle charge 
-  pZ = trackParam->Pz();
-  pX = trackParam->Px(); 
-  pY = trackParam->Py();
-  pT = TMath::Sqrt(pX*pX+pY*pY);
-
-  if (TMath::Abs(pZ) <= 0) return;
-  x[2] = zEnd/2;
-  x[0] = x[2]*trackParam->GetNonBendingSlope();  
-  x[1] = x[2]*trackParam->GetBendingSlope();
-
-  // Take magn. field value at position x.
-  if (fgkField) fgkField->Field(x,b);
-  else {
-    cout<<"F-AliMUONTrackExtrap::FieldCorrection: fgkField = 0x0"<<endl;
-    exit(-1);
+  /// Calculate the total momentum energy loss in-between the track position and the vertex assuming a linear propagation
+  
+  if (trackParam->GetZ() == zVtx) return 0.; // nothing to be done if already at vertex
+  
+  // Check whether the geometry is available
+  if (!gGeoManager) {
+    cout<<"E-AliMUONTrackExtrap::TotalMomentumEnergyLoss: no TGeo"<<endl;
+    return 0.;
   }
-  bZ =  b[2];
-  // Transverse momentum rotation
-  // Parameterized with the study of DeltaPhi = phiReco - phiGen as a function of pZ.
-  Double_t phiShift = c*0.436*0.0003*bZ*zEnd/pZ; 
- // Rotate momentum around Z axis.
-  pXNew = pX*TMath::Cos(phiShift) - pY*TMath::Sin(phiShift);
-  pYNew = pX*TMath::Sin(phiShift) + pY*TMath::Cos(phiShift);
-  trackParam->SetBendingSlope(pYNew/pZ);
-  trackParam->SetNonBendingSlope(pXNew/pZ);
   
-  trackParam->SetInverseBendingMomentum(c/TMath::Sqrt(pYNew*pYNew+pZ*pZ));
+  // Get encountered material correction parameters assuming linear propagation from vertex to the track position
+  Double_t trackXYZOut[3];
+  trackXYZOut[0] = trackParam->GetNonBendingCoor();
+  trackXYZOut[1] = trackParam->GetBendingCoor();
+  trackXYZOut[2] = trackParam->GetZ();
+  Double_t trackXYZIn[3];
+  trackXYZIn[0] = xVtx;
+  trackXYZIn[1] = yVtx;
+  trackXYZIn[2] = zVtx;
+  Double_t pTot = trackParam->P();
+  Double_t pathLength = 0.;
+  Double_t f0 = 0.;
+  Double_t f1 = 0.;
+  Double_t f2 = 0.;
+  Double_t meanRho = 0.;
+  Double_t totalELoss = 0.;
+  GetAbsorberCorrectionParam(trackXYZIn,trackXYZOut,pTot,pathLength,f0,f1,f2,meanRho,totalELoss);
+  
+  return totalELoss;
+}
+
+  //__________________________________________________________________________
+Double_t AliMUONTrackExtrap::BetheBloch(Double_t pTotal, Double_t pathLength, Double_t rho, Double_t atomicA, Double_t atomicZ)
+{
+  /// Returns the mean total momentum energy loss of muon with total momentum='pTotal'
+  /// in the absorber layer of lenght='pathLength', density='rho', A='atomicA' and Z='atomicZ'
+  Double_t muMass = 0.105658369; // GeV
+  Double_t eMass = 0.510998918e-3; // GeV
+  Double_t k = 0.307075e-3; // GeV.g^-1.cm^2
+  Double_t i = 9.5e-9; // mean exitation energy per atomic Z (GeV)
+  Double_t p2=pTotal*pTotal;
+  Double_t beta2=p2/(p2 + muMass*muMass);
+  
+  Double_t w = k * rho * pathLength * atomicZ / atomicA / beta2;
+  
+  if (beta2/(1-beta2)>3.5*3.5)
+     return w * (log(2.*eMass*3.5/(i*atomicZ)) + 0.5*log(beta2/(1-beta2)) - beta2);
+
+  return w * (log(2.*eMass*beta2/(1-beta2)/(i*atomicZ)) - beta2);
 }
 
  //__________________________________________________________________________
 void AliMUONTrackExtrap::ExtrapOneStepHelix(Double_t charge, Double_t step, Double_t *vect, Double_t *vout)
 {
+/// <pre>
 ///    ******************************************************************
 ///    *                                                                *
 ///    *  Performs the tracking of one step in a magnetic field         *
@@ -468,6 +804,7 @@ void AliMUONTrackExtrap::ExtrapOneStepHelix(Double_t charge, Double_t step, Doub
 ///    *       modified  v.perevoztchikov
 ///    *                                                                *
 ///    ******************************************************************
+/// </pre>
 
 // modif: everything in double precision
 
@@ -566,6 +903,7 @@ void AliMUONTrackExtrap::ExtrapOneStepHelix(Double_t charge, Double_t step, Doub
  //__________________________________________________________________________
 void AliMUONTrackExtrap::ExtrapOneStepHelix3(Double_t field, Double_t step, Double_t *vect, Double_t *vout)
 {
+/// <pre>
 ///    ******************************************************************
 ///    *                                                                *
 ///    *       Tracking routine in a constant field oriented            *
@@ -578,6 +916,7 @@ void AliMUONTrackExtrap::ExtrapOneStepHelix3(Double_t field, Double_t step, Doub
 ///    *       Rewritten  V.Perevoztchikov
 ///    *                                                                *
 ///    ******************************************************************
+/// </pre>
 
     Double_t hxp[3];
     Double_t h4, hp, rho, tet;
@@ -638,9 +977,11 @@ void AliMUONTrackExtrap::ExtrapOneStepHelix3(Double_t field, Double_t step, Doub
 
     return;
 }
+
  //__________________________________________________________________________
 void AliMUONTrackExtrap::ExtrapOneStepRungekutta(Double_t charge, Double_t step, Double_t* vect, Double_t* vout)
 {
+/// <pre>
 ///    ******************************************************************
 ///    *                                                                *
 ///    *  Runge-Kutta method for tracking a particle through a magnetic *
@@ -662,6 +1003,7 @@ void AliMUONTrackExtrap::ExtrapOneStepRungekutta(Double_t charge, Double_t step,
 ///    *                                                                *
 ///    *                                                                *
 ///    ******************************************************************
+/// </pre>
 
     Double_t h2, h4, f[4];
     Double_t xyzt[3], a, b, c, ph,ph2;
@@ -881,6 +1223,7 @@ void AliMUONTrackExtrap::ExtrapOneStepRungekutta(Double_t charge, Double_t step,
 
     return;
 }
+
 //___________________________________________________________
  void  AliMUONTrackExtrap::GetField(Double_t *Position, Double_t *Field)
 {
@@ -899,4 +1242,3 @@ void AliMUONTrackExtrap::ExtrapOneStepRungekutta(Double_t charge, Double_t step,
 
   return;
 }
-