]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - ITS/UPGRADE/KMCDetector.cxx
end-of-line normalization
[u/mrichter/AliRoot.git] / ITS / UPGRADE / KMCDetector.cxx
index f2c63c1212eeeb2b4f480e6562da562b4e1f8b92..1c9ce095d67e7f6dc5ca4981810162de84fb408e 100755 (executable)
-#include "KMCDetector.h"\r
-#include <TMath.h>\r
-#include <TH1F.h>\r
-#include <TProfile.h>\r
-#include <TF1.h>\r
-#include <TMatrixD.h>\r
-#include <TGraph.h>\r
-#include <TAxis.h>\r
-#include <TFormula.h>\r
-#include <TCanvas.h>\r
-#include <TEllipse.h>\r
-#include <TText.h>\r
-#include <TRandom3.h>\r
-#include <TGraphErrors.h>\r
-#include <TStopwatch.h>\r
-\r
-/***********************************************************\r
-\r
-Fast Simulation tool for Inner Tracker Systems\r
-\r
-***********************************************************/\r
-\r
-\r
-#define RIDICULOUS 999999 // A ridiculously large resolution (cm) to flag a dead detector\r
-\r
-#define Luminosity    1.e27       // Luminosity of the beam (LHC HI == 1.e27, RHIC II == 8.e27 )\r
-#define SigmaD        6.0         // Size of the interaction diamond (cm) (LHC = 6.0 cm)\r
-#define dNdEtaMinB    1//950//660//950           // Multiplicity per unit Eta  (AuAu MinBias = 170, Central = 700)\r
-// #define dNdEtaCent    2300//15000 //1600//2300        // Multiplicity per unit Eta  (LHC at 5.5 TeV not known)\r
-\r
-#define CrossSectionMinB         8    // minB Cross section for event under study (PbPb MinBias ~ 8 Barns)\r
-#define AcceptanceOfTpcAndSi     1 //1//0.60 //0.35  // Assumed geometric acceptance (efficiency) of the TPC and Si detectors\r
-#define UPCBackgroundMultiplier  1.0   // Increase multiplicity in detector (0.0 to 1.0 * UPCRate ) (eg 1.0)\r
-#define OtherBackground          0.0   // Increase multiplicity in detector (0.0 to 1.0 * minBias)  (eg 0.0)\r
-#define EfficiencySearchFlag     2     // Define search method:\r
-                                       // -> ChiSquarePlusConfLevel = 2, ChiSquare = 1, Simple = 0.  \r
-\r
-#define PionMass                 0.139  // Mass of the Pion\r
-#define KaonMass                 0.498  // Mass of the Kaon\r
-#define D0Mass                   1.865  // Mass of the D0\r
-\r
-//TMatrixD *probKomb; // table for efficiency kombinatorics\r
-\r
-ClassImp(KMCProbe)\r
-\r
-Int_t    KMCProbe::fgNITSLayers = 0;\r
-Double_t KMCProbe::fgMissingHitPenalty = 2.;\r
-//__________________________________________________________________________\r
-KMCProbe& KMCProbe::operator=(const KMCProbe& src) \r
-{\r
-  if (this!=&src) {\r
-    AliExternalTrackParam::operator=(src);\r
-    fMass = src.fMass;\r
-    fChi2 = src.fChi2;\r
-    fHits = src.fHits;\r
-    fFakes = src.fFakes;\r
-    fNHits = src.fNHits;\r
-    fNHitsITS = src.fNHitsITS;\r
-    fNHitsITSFake = src.fNHitsITSFake;\r
-    fInnLrCheck     = src.fInnLrCheck;\r
-    for (int i=kMaxITSLr;i--;) fClID[i] = src.fClID[i];\r
-  }\r
-  return *this;\r
-}\r
-\r
-//__________________________________________________________________________\r
-KMCProbe::KMCProbe(KMCProbe& src) \r
-  : AliExternalTrackParam(src),\r
-    fMass(src.fMass),\r
-    fChi2(src.fChi2),\r
-    fHits(src.fHits),\r
-    fFakes(src.fFakes),\r
-    fNHits(src.fNHits),\r
-    fNHitsITS(src.fNHitsITS),\r
-    fNHitsITSFake(src.fNHitsITSFake),\r
-    fInnLrCheck(src.fInnLrCheck)\r
-{\r
-  for (int i=kMaxITSLr;i--;) fClID[i] = src.fClID[i];\r
-}\r
-\r
-//__________________________________________________________________________\r
-void KMCProbe::ResetCovMat()\r
-{\r
-  // reset errors\r
-  double *trCov  = (double*)GetCovariance();\r
-  double *trPars = (double*)GetParameter();\r
-  const double kLargeErr2Coord = 50*50;\r
-  const double kLargeErr2Dir = 0.6*0.6;\r
-  const double kLargeErr2PtI = 0.5*0.5;\r
-  for (int ic=15;ic--;) trCov[ic] = 0.;\r
-  trCov[kY2]   = trCov[kZ2]   = kLargeErr2Coord; \r
-  trCov[kSnp2] = trCov[kTgl2] = kLargeErr2Dir;\r
-  trCov[kPtI2] = kLargeErr2PtI*trPars[kPtI]*trPars[kPtI];\r
-  //\r
-}\r
-\r
-//__________________________________________________________________________\r
-void KMCProbe::Print(Option_t* option) const\r
-{\r
-  printf("M=%.3f Chi2=%7.2f (Norm:%6.2f|%d) Hits: Total:%d ITS:%d ITSFakes:%d | Y:%+8.4f Z: %+8.4f |", \r
-        fMass,fChi2,GetNormChi2(kTRUE),fInnLrCheck,fNHits,fNHitsITS,fNHitsITSFake, GetY(),GetZ());\r
-  for (int i=0;i<fgNITSLayers;i++) {\r
-    if (!IsHit(i)) printf(".");\r
-    else printf("%c",IsHitFake(i) ? '-':'+');\r
-  }\r
-  printf("|%s\n",IsKilled() ? " KILLED":"");\r
-  TString opt = option;\r
-  if (!opt.IsNull()) AliExternalTrackParam::Print(option);\r
-}\r
-\r
-//__________________________________________________________________________\r
-Int_t KMCProbe::Compare(const TObject* obj) const\r
-{\r
-  // compare to tracks\r
-  const KMCProbe* trc = (KMCProbe*) obj;\r
-  if (trc->IsKilled()) {\r
-    if (IsKilled()) return 0;\r
-    return -1;\r
-  }\r
-  else if (IsKilled()) return 1;\r
-  double chi2a = GetNormChi2(kTRUE);\r
-  double chi2b = trc->GetNormChi2(kTRUE);\r
-  if (chi2a<chi2b) return  -1;\r
-  if (chi2a>chi2b) return   1;\r
-  return 0;\r
-}\r
-\r
-//__________________________________________________________________________\r
-Bool_t KMCProbe::GetXatLabR(Double_t r,Double_t &x, Double_t bz, Int_t dir) const\r
-{\r
-  // Get local X of the track position estimated at the radius lab radius r. \r
-  // The track curvature is accounted exactly\r
-  //\r
-  // The flag "dir" can be used to remove the ambiguity of which intersection to take (out of 2 possible)\r
-  // 0  - take the intersection closest to the current track position\r
-  // >0 - go along the track (increasing fX)\r
-  // <0 - go backward (decreasing fX)\r
-  //\r
-  // special case of R=0\r
-  if (r<kAlmost0) {x=0; return kTRUE;}\r
-\r
-  const double* pars = GetParameter();\r
-  const Double_t &fy=pars[0], &sn = pars[2];\r
-  //\r
-  double fx = GetX();\r
-  double crv = GetC(bz);\r
-  if (TMath::Abs(crv)<=kAlmost0) { // this is a straight track\r
-    if (TMath::Abs(sn)>=kAlmost1) { // || to Y axis\r
-      double det = (r-fx)*(r+fx);\r
-      if (det<0) return kFALSE;     // does not reach raduis r\r
-      x = fx;\r
-      if (dir==0) return kTRUE;\r
-      det = TMath::Sqrt(det);\r
-      if (dir>0) {                       // along the track direction\r
-       if (sn>0) {if (fy>det)  return kFALSE;} // track is along Y axis and above the circle\r
-       else      {if (fy<-det) return kFALSE;} // track is against Y axis amd belo the circle\r
-      }\r
-      else if(dir>0) {                                    // agains track direction\r
-       if (sn>0) {if (fy<-det) return kFALSE;} // track is along Y axis\r
-        else if (fy>det)  return kFALSE;        // track is against Y axis\r
-      }\r
-    }\r
-    else if (TMath::Abs(sn)<=kAlmost0) { // || to X axis\r
-      double det = (r-fy)*(r+fy);\r
-      if (det<0) return kFALSE;     // does not reach raduis r\r
-      det = TMath::Sqrt(det);\r
-      if (!dir) {\r
-       x = fx>0  ? det : -det;    // choose the solution requiring the smalest step\r
-       return kTRUE;\r
-      }\r
-      else if (dir>0) {                    // along the track direction\r
-       if      (fx > det) return kFALSE;  // current point is in on the right from the circle\r
-       else if (fx <-det) x = -det;       // on the left\r
-       else               x =  det;       // within the circle\r
-      }\r
-      else {                               // against the track direction\r
-       if      (fx <-det) return kFALSE;  \r
-       else if (fx > det) x =  det;\r
-       else               x = -det;\r
-      }\r
-    }\r
-    else {                                 // general case of straight line\r
-      double cs = TMath::Sqrt((1-sn)*(1+sn));\r
-      double xsyc = fx*sn-fy*cs;\r
-      double det = (r-xsyc)*(r+xsyc);\r
-      if (det<0) return kFALSE;    // does not reach raduis r\r
-      det = TMath::Sqrt(det);\r
-      double xcys = fx*cs+fy*sn;\r
-      double t = -xcys;\r
-      if (dir==0) t += t>0 ? -det:det;  // chose the solution requiring the smalest step\r
-      else if (dir>0) {                 // go in increasing fX direction. ( t+-det > 0)\r
-       if (t>=-det) t += -det;         // take minimal step giving t>0\r
-       else return kFALSE;             // both solutions have negative t\r
-      }\r
-      else {                            // go in increasing fx direction. (t+-det < 0)\r
-       if (t<det) t -= det;            // take minimal step giving t<0\r
-       else return kFALSE;             // both solutions have positive t\r
-      }\r
-      x = fx + cs*t;\r
-    }\r
-  }\r
-  else {                                 // helix\r
-    // get center of the track circle\r
-    double tR = 1./crv;   // track radius (for the moment signed)\r
-    double cs = TMath::Sqrt((1-sn)*(1+sn));\r
-    double x0 = fx - sn*tR;\r
-    double y0 = fy + cs*tR;\r
-    double r0 = TMath::Sqrt(x0*x0+y0*y0);\r
-    //    printf("Xc:%+e Yc:%+e\n",x0,y0);\r
-    //\r
-    if (r0<=kAlmost0) {\r
-      AliDebug(2,Form("r0 = %f",r0));\r
-      return kFALSE;\r
-    }            // the track is concentric to circle\r
-    tR = TMath::Abs(tR);\r
-    double tR2r0 = tR/r0;\r
-    double g = 0.5*(r*r/(r0*tR) - tR2r0 - 1./tR2r0);\r
-    double det = (1.-g)*(1.+g);\r
-    if (det<0) {\r
-      AliDebug(2,Form("g=%f tR=%f r0=%f\n",g,tR, r0));\r
-      return kFALSE;\r
-    }         // does not reach raduis r\r
-    det = TMath::Sqrt(det);\r
-    //\r
-    // the intersection happens in 2 points: {x0+tR*C,y0+tR*S} \r
-    // with C=f*c0+-|s0|*det and S=f*s0-+c0 sign(s0)*det\r
-    // where s0 and c0 make direction for the circle center (=x0/r0 and y0/r0)\r
-    //\r
-    double tmp = 1.+g*tR2r0;\r
-    x = x0*tmp; \r
-    double y = y0*tmp;\r
-    if (TMath::Abs(y0)>kAlmost0) { // when y0==0 the x,y is unique\r
-      double dfx = tR2r0*TMath::Abs(y0)*det;\r
-      double dfy = tR2r0*x0*TMath::Sign(det,y0);\r
-      if (dir==0) {                    // chose the one which corresponds to smallest step \r
-       double delta = (x-fx)*dfx-(y-fy)*dfy; // the choice of + in C will lead to smaller step if delta<0\r
-       if (delta<0) x += dfx;\r
-       else         x -= dfx;\r
-      }\r
-      else if (dir>0) {  // along track direction: x must be > fx\r
-       x -= dfx; // try the smallest step (dfx is positive)\r
-       if (x<fx && (x+=dfx+dfx)<fx) return kFALSE;\r
-      }\r
-      else { // backward: x must be < fx\r
-       x += dfx; // try the smallest step (dfx is positive)\r
-       if (x>fx && (x-=dfx+dfx)>fx) return kFALSE;\r
-      }\r
-    }\r
-    else { // special case: track touching the circle just in 1 point\r
-      if ( (dir>0&&x<fx) || (dir<0&&x>fx) ) return kFALSE; \r
-    }\r
-  }\r
-  //\r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________\r
-Bool_t KMCProbe::PropagateToR(double r, double b, int dir) \r
-{\r
-  // go to radius R\r
-  //\r
-  double xR = 0;\r
-  double rr = r*r;\r
-  int iter = 0;\r
-  const double kTiny = 1e-4;\r
-  while(1) {\r
-    if (!GetXatLabR(r ,xR, b, dir)) {\r
-      //      printf("Track with pt=%f cannot reach radius %f\n",Pt(),r);\r
-      //      Print("l");\r
-      return kFALSE;\r
-    }\r
-    \r
-    if (!PropagateTo(xR, b)) {\r
-      if (AliLog::GetGlobalDebugLevel()>2) {\r
-       printf("Failed to propagate to X=%f for R=%f\n",xR,r); \r
-       Print("l"); \r
-      }\r
-      return kFALSE;\r
-    }\r
-    double rcurr2 = xR*xR + GetY()*GetY();\r
-    if (TMath::Abs(rcurr2-rr)<kTiny || rr<kAlmost0) return kTRUE;\r
-    //\r
-    // two radii correspond to this X...\r
-    double pos[3]; GetXYZ(pos);\r
-    double phi = TMath::ATan2(pos[1],pos[0]);\r
-    if (!Rotate(phi)) {\r
-      if (AliLog::GetGlobalDebugLevel()>2) {\r
-       printf("Failed to rotate to %f to propagate to R=%f\n",phi,r); \r
-       Print("l"); \r
-      }\r
-      return kFALSE;\r
-    }\r
-    if (++iter>8) {\r
-      if (AliLog::GetGlobalDebugLevel()>2) {\r
-       printf("Failed to propagate to R=%f after %d steps\n",r,iter); \r
-       Print("l"); \r
-      }\r
-      return kFALSE;\r
-    }\r
-  } \r
-  return kTRUE;\r
-}\r
-\r
-\r
-//__________________________________________________________________________\r
-Bool_t KMCProbe::CorrectForMeanMaterial(const KMCLayer* lr, Bool_t inward)\r
-{\r
-  //  printf("before at r=%.1f p=%.4f\n",lr->fR, P());\r
-  if (AliExternalTrackParam::CorrectForMeanMaterial(lr->fx2X0, inward ? lr->fXRho : -lr->fXRho, GetMass() , kTRUE)) {\r
-    //  printf("after  at r=%.1f p=%.4f\n",lr->fR, P());\r
-    return kTRUE;\r
-  }\r
-  AliDebug(2,Form("Failed to apply material correction, X/X0=%.4f", lr->fx2X0));\r
-  if (AliLog::GetGlobalDebugLevel()>1) Print();\r
-  return kFALSE;\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-ClassImp(KMCCluster)\r
-\r
-//_________________________________________________________________________\r
-KMCCluster::KMCCluster(KMCCluster &src) \r
-: TObject(src),\r
-  fY(src.fY),fZ(src.fZ),fX(src.fX),fPhi(src.fPhi)\r
-{}\r
-\r
-//__________________________________________________________________________\r
-KMCCluster& KMCCluster::operator=(const KMCCluster& src) \r
-{\r
-  if (this!=&src) {\r
-    TObject::operator=(src);\r
-    fY = src.fY;\r
-    fZ = src.fZ;\r
-    fX = src.fX;\r
-    fPhi = src.fPhi;\r
-  }\r
-  return *this;\r
-}\r
-\r
-//_________________________________________________________________________\r
-void KMCCluster::Print(Option_t *) const \r
-{\r
-  printf(" Local YZ = (%3.4lf,%3.4lf) | X=%3.4lf  phi: %+.3f %s\n",fY,fZ,fX,fPhi,IsKilled()?"Killed":""); \r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-ClassImp(KMCLayer)\r
-\r
-Double_t KMCLayer::fgDefEff = 1.0;\r
-//__________________________________________________________________________\r
-KMCLayer::KMCLayer(char *name) : \r
-  TNamed(name,name),fR(0),fx2X0(0),fPhiRes(0),fZRes(0),fEff(0),fIsDead(kFALSE),fType(-1),fActiveID(-1),fSig2EstD(999),fSig2EstZ(999),\r
-  fClCorr(),fClMC(),fClBg("KMCCluster",5), fTrCorr(), fTrMC("KMCProbe",5)\r
-{\r
-  Reset();\r
-}\r
-\r
-//__________________________________________________________________________\r
-void KMCLayer::Reset() \r
-{\r
-  fTrCorr.Reset();\r
-  fClCorr.Reset();\r
-  ResetMC();\r
-  fSig2EstD = fSig2EstZ = 999;\r
-  //\r
-}\r
-\r
-//__________________________________________________________________________\r
-KMCProbe* KMCLayer::AddMCTrack(KMCProbe* src) \r
-{\r
-  int ntr = GetNMCTracks(); \r
-  KMCProbe* prb = 0;\r
-  if (src) prb = new(fTrMC[ntr]) KMCProbe(*src);\r
-  else     prb = new(fTrMC[ntr]) KMCProbe();\r
-  if (!IsDead()) prb->ResetHit(GetActiveID());\r
-  return prb;\r
-}\r
-\r
-//__________________________________________________________________________\r
-void KMCLayer::Print(Option_t *opt) const\r
-{\r
-  printf("Lr%3d(A%3d) %10s R=%5.1f X2X0=%.3f XRho=%.3f SigY=%.4f SigZ=%.4f Eff:%4.2f\n",GetUniqueID(),fActiveID,GetName(), fR, fx2X0,fXRho,fPhiRes,fZRes,fEff);\r
-  TString opts = opt; opts.ToLower();\r
-  if (opts.Contains("c")) {\r
-    printf("Clusters: MC: %+7.4f:%+7.4f Ideal: %+7.4f:%+7.4f  NBgCl: %3d NTrMC: %4d\n",fClMC.fY,fClMC.fZ, fClCorr.fY,fClCorr.fZ, GetNBgClusters(),GetNMCTracks());\r
-  }\r
-}\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-Double_t KMCDetector::fgVtxConstraint[2]={-1,-1};\r
-\r
-ClassImp(KMCDetector)\r
-KMCDetector::KMCDetector() :\r
-TNamed("test_detector","detector"),\r
-  fNLayers(0),\r
-  fNActiveLayers(0),\r
-  fNActiveITSLayers(0),\r
-  fLastActiveLayer(-1),\r
-  fLastActiveITSLayer(-1),\r
-  fLastActiveLayerTracked(-1),\r
-  fBFieldG(5.),\r
-  fLhcUPCscale(1.0),    \r
-  fIntegrationTime(0.02), // in ms\r
-  fConfLevel(0.0027),      // 0.27 % -> 3 sigma confidence\r
-  fAvgRapidity(0.45),      // Avg rapidity, MCS calc is a function of crossing angle\r
-  fParticleMass(0.140),    // Standard: pion mass \r
-  fMaxRadiusSlowDet(10.),\r
-  fAtLeastCorr(-1),     // if -1, then correct hit on all ITS layers\r
-  fAtLeastFake(1),       // if at least x fakes, track is considered fake ...\r
-  fdNdEtaCent(2300),\r
-  fMaxChi2Cl(25.),\r
-  fMaxNormChi2NDF(5.),\r
-  fMinITSHits(4),\r
-//\r
-  fMaxChi2ClSQ(4.), // precalulated internally\r
-  fMaxSeedToPropagate(300),\r
-//\r
-  fUseBackground(kFALSE),\r
-  fBgYMin(1e6),fBgYMax(-1e6),fBgZMin(1e6),fBgZMax(-1e6),\r
-  fBgYMinTr(100),fBgYMaxTr(100),fBgZMinTr(100),fBgZMaxTr(100),fNBgLimits(0),\r
-  fDensFactorEta(1.),\r
-//\r
-  fUpdCalls(0),\r
-  fHMCLrResidRPhi(0),\r
-  fHMCLrResidZ(0),\r
-  fHMCLrChi2(0),\r
-  fPattITS(0)\r
-{\r
-  //\r
-  // default constructor\r
-  //\r
-  //  fLayers = new TObjArray();\r
-  RequireMaxChi2Cl(fMaxChi2Cl); // just to precalulate default square\r
-}\r
-\r
-KMCDetector::KMCDetector(char *name, char *title)\r
-  : TNamed(name,title),\r
-    fNLayers(0),\r
-    fNActiveLayers(0),\r
-    fNActiveITSLayers(0),\r
-    fLastActiveLayer(-1),\r
-    fLastActiveITSLayer(-1),    \r
-    fLastActiveLayerTracked(-1),\r
-    fBFieldG(5.0),\r
-    fLhcUPCscale(1.0),\r
-    fIntegrationTime(0.02),  // in ms\r
-    fConfLevel(0.0027),      // 0.27 % -> 3 sigma confidence\r
-    fAvgRapidity(0.45),      // Avg rapidity, MCS calc is a function of crossing angle\r
-    fParticleMass(0.140),     // Standard: pion mass\r
-    fMaxRadiusSlowDet(10.),\r
-    fAtLeastCorr(-1),     // if -1, then correct hit on all ITS layers\r
-    fAtLeastFake(1),       // if at least x fakes, track is considered fake ...\r
-    fdNdEtaCent(2300),\r
-    fMaxChi2Cl(9.),\r
-    fMaxNormChi2NDF(5.),\r
-    fMinITSHits(4),\r
-    //\r
-    fMaxChi2ClSQ(3.), // precalulated internally\r
-    fMaxSeedToPropagate(50),\r
-    //\r
-    fUseBackground(kFALSE),\r
-    fBgYMin(1e6),fBgYMax(-1e6),fBgZMin(1e6),fBgZMax(-1e6),\r
-    fBgYMinTr(100),fBgYMaxTr(100),fBgZMinTr(100),fBgZMaxTr(100),fNBgLimits(0),\r
-    fDensFactorEta(1.),\r
-    //\r
-    fUpdCalls(0),\r
-    fHMCLrResidRPhi(0),\r
-    fHMCLrResidZ(0),\r
-    fHMCLrChi2(0),\r
-    fPattITS(0)\r
-{\r
-  //\r
-  // default constructor, that set the name and title\r
-  //\r
-  //  fLayers = new TObjArray();\r
-}\r
-KMCDetector::~KMCDetector() { // \r
-  // virtual destructor\r
-  //\r
-  //  delete fLayers;\r
-}\r
-\r
-void KMCDetector::InitMCWatchHistos()\r
-{\r
-  // init utility histos used for MC tuning\r
-  enum {kNBinRes=1000};\r
-  const double kMaxResidRPhi=1.0,kMaxResidZ=1.0,kMaxChi2=50;\r
-  int nlr = fNActiveITSLayers;\r
-  TString nam = "mc_residrhi";\r
-  TString tit = "MC $Delta Cl-Tr R#phi";\r
-  fHMCLrResidRPhi = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxResidRPhi,nlr,-0.5,nlr-0.5);\r
-  fHMCLrResidRPhi->GetXaxis()->SetTitle("cl-tr #Delta r#phi");\r
-  fHMCLrResidRPhi->Sumw2();\r
-    //\r
-  nam = "mc_residz";\r
-  tit = "MC $Delta Cl-Tr Z";\r
-  fHMCLrResidZ = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxResidZ,nlr,-0.5,nlr-0.5);\r
-  fHMCLrResidZ->GetXaxis()->SetTitle("cl-tr #Delta z");\r
-  fHMCLrResidZ->Sumw2();\r
-    //\r
-  nam = "mc_chi2";\r
-  tit = "MC #chi^{2} Cl-Tr Z";\r
-  fHMCLrChi2 = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxChi2,nlr,-0.5,nlr-0.5);\r
-  fHMCLrChi2->GetXaxis()->SetTitle("cl-tr #chi^{2}");\r
-  fHMCLrChi2->Sumw2();\r
-  //\r
-  SetBit(kUtilHisto);\r
-}\r
-\r
-\r
-void KMCDetector::AddLayer(char *name, Float_t radius, Float_t x2X0, Float_t xrho, Float_t phiRes, Float_t zRes, Float_t eff) {\r
-  //\r
-  // Add additional layer to the list of layers (ordered by radius)\r
-  // \r
-\r
-  KMCLayer *newLayer = (KMCLayer*) fLayers.FindObject(name);\r
-\r
-  if (!newLayer) {\r
-    newLayer = new KMCLayer(name);\r
-    newLayer->fR = radius;\r
-    newLayer->fx2X0 = x2X0;\r
-    newLayer->fXRho  = xrho;\r
-    newLayer->fPhiRes = phiRes;\r
-    newLayer->fZRes = zRes;\r
-    eff = TMath::Min(1.f,eff);\r
-    newLayer->fEff = eff <0 ? KMCLayer::GetDefEff() : eff;\r
-    newLayer->fActiveID = -2;\r
-    TString lname = name;\r
-    newLayer->fType = KMCLayer::kTypeNA;\r
-    if      (lname.Contains("tpc")) newLayer->fType = KMCLayer::kTPC;\r
-    else if (lname.Contains("its")) newLayer->fType = KMCLayer::kITS;\r
-    if (lname.Contains("vertex")) newLayer->SetBit(KMCLayer::kBitVertex);\r
-    //\r
-    if (newLayer->fType==KMCLayer::kTypeNA) printf("Attention: the layer %s has undefined type\n",name);\r
-    //\r
-    newLayer->fIsDead =  (newLayer->fPhiRes==RIDICULOUS && newLayer->fZRes==RIDICULOUS);\r
-    //\r
-    if (fLayers.GetEntries()==0) \r
-      fLayers.Add(newLayer);\r
-    else {\r
-      //\r
-      for (Int_t i = 0; i<fLayers.GetEntries(); i++) {\r
-       KMCLayer *l = (KMCLayer*)fLayers.At(i);\r
-       if (radius<l->fR) { fLayers.AddBefore(l,newLayer); break; }\r
-         if (radius>l->fR && (i+1)==fLayers.GetEntries() ) fLayers.Add(newLayer); // even bigger then last one\r
-      }\r
-      //\r
-    }\r
-    //\r
-    ClassifyLayers();\r
-    //\r
-  } else {\r
-    printf("Layer with the name %s does already exist\n",name);\r
-  }\r
-}\r
-\r
-//____________________________________________________________\r
-void KMCDetector::ClassifyLayers()\r
-{\r
-  // assign active Id's, etc\r
-  fLastActiveLayer = -1;\r
-  fLastActiveITSLayer = -1;\r
-  fNActiveLayers = 0;\r
-  fNActiveITSLayers = 0;\r
-  //\r
-  int nl = GetNLayers();\r
-  for (int il=0;il<nl;il++) {\r
-    KMCLayer* lr = GetLayer(il);\r
-    lr->SetUniqueID(il);\r
-    if (!lr->IsDead()) {\r
-      fLastActiveLayer = il; \r
-      lr->fActiveID = fNActiveLayers++;\r
-      if (lr->IsITS()) {\r
-       fLastActiveITSLayer = il;\r
-       fNActiveITSLayers++;\r
-      }\r
-    }\r
-  }\r
-  //\r
-  KMCProbe::SetNITSLayers(fNActiveITSLayers);\r
-}\r
-\r
-//____________________________________________________________\r
-void KMCDetector::KillLayer(char *name) {\r
-  //\r
-  // Marks layer as dead. Contribution only by Material Budget\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot mark as dead\n",name);\r
-  else {\r
-     tmp->fPhiRes = 999999;\r
-     tmp->fZRes = 999999;\r
-     tmp->fIsDead = kTRUE;\r
-     ClassifyLayers();\r
-  }\r
-}\r
-\r
-void KMCDetector::SetRadius(char *name, Float_t radius) {\r
-  //\r
-  // Set layer radius [cm]\r
-  //\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  //\r
-  if (!tmp) {\r
-    printf("Layer %s not found - cannot set radius\n",name);\r
-  } else {\r
-      \r
-    Float_t tmpRadL  = tmp->fx2X0;\r
-    Float_t tmpPhiRes = tmp->fPhiRes;\r
-    Float_t tmpZRes = tmp->fZRes;\r
-    Float_t tmpXRho = tmp->fXRho;\r
-    RemoveLayer(name); // so that the ordering is correct\r
-    AddLayer(name,radius,tmpRadL,tmpXRho,tmpPhiRes,tmpZRes);\r
-  }\r
-}\r
-\r
-Float_t KMCDetector::GetRadius(char *name) {\r
-  //\r
-  // Return layer radius [cm]\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot get radius\n",name);\r
-  else \r
-    return tmp->fR;\r
-\r
-  return 0;\r
-}\r
-\r
-void KMCDetector::SetRadiationLength(char *name, Float_t x2X0) {\r
-  //\r
-  // Set layer material [cm]\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot set layer material\n",name);\r
-  else {\r
-    tmp->fx2X0 = x2X0;\r
-  }\r
-}\r
-\r
-Float_t KMCDetector::GetRadiationLength(char *name) {\r
-  //\r
-  // Return layer radius [cm]\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot get layer material\n",name);\r
-  else \r
-    return tmp->fx2X0;\r
-    \r
-  return 0;\r
-  \r
-}\r
-\r
-void KMCDetector::SetResolution(char *name, Float_t phiRes, Float_t zRes) {\r
-  //\r
-  // Set layer resolution in [cm]\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot set resolution\n",name);\r
-  else {\r
-    tmp->fPhiRes = phiRes;\r
-    tmp->fZRes = zRes;\r
-    tmp->fIsDead = (zRes==RIDICULOUS && phiRes==RIDICULOUS);\r
-    ClassifyLayers();\r
-  }\r
-}\r
-\r
-Float_t KMCDetector::GetResolution(char *name, Int_t axis) {\r
-  //\r
-  // Return layer resolution in [cm]\r
-  // axis = 0: resolution in rphi\r
-  // axis = 1: resolution in z\r
-  //\r
-\r
-  KMCLayer *tmp = GetLayer(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot get resolution\n",name);\r
-  else {\r
-    if (axis==0) return tmp->fPhiRes;\r
-    if (axis==1) return tmp->fZRes;\r
-    printf("error: axis must be either 0 or 1 (rphi or z axis)\n");\r
-  }\r
-  return 0;\r
-}\r
-\r
-void KMCDetector::SetLayerEfficiency(char *name, Float_t eff) {\r
-  //\r
-  // Set layer efficnecy (prop that his is missed within this layer) \r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot set layer efficiency\n",name);\r
-  else {\r
-    tmp->fEff = eff;\r
-  }\r
-}\r
-\r
-Float_t KMCDetector::GetLayerEfficiency(char *name) {\r
-  //\r
-  // Get layer efficnecy (prop that his is missed within this layer) \r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot get layer efficneicy\n",name);\r
-  else \r
-    return tmp->fEff;\r
-    \r
-  return 0;\r
-  \r
-}\r
-\r
-void KMCDetector::RemoveLayer(char *name) {\r
-  //\r
-  // Removes a layer from the list\r
-  //\r
-\r
-  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);\r
-  if (!tmp) \r
-    printf("Layer %s not found - cannot remove it\n",name);\r
-  else {\r
-    fLayers.Remove(tmp);\r
-    ClassifyLayers();\r
-  }\r
-}\r
-\r
-\r
-void KMCDetector::PrintLayout() {\r
-  //\r
-  // Prints the detector layout\r
-  //\r
-\r
-  printf("Detector %s: \"%s\"\n",GetName(),GetTitle());\r
-  \r
-  if (fLayers.GetEntries()>0) \r
-    printf("  Name \t\t r [cm] \t  X0 \t  phi & z res [um]\n");\r
-\r
-  KMCLayer *tmp = 0;\r
-  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {\r
-    tmp = (KMCLayer*)fLayers.At(i);\r
-  \r
-    // don't print all the tpc layers\r
-    TString name(tmp->GetName());\r
-    if (name.Contains("tpc") && (!name.Contains("tpc_0")) ) continue;\r
-\r
-    printf("%d. %s \t %03.2f   \t%1.4f\t  ",i,\r
-          tmp->GetName(), tmp->fR, tmp->fx2X0);\r
-    if (tmp->fPhiRes==RIDICULOUS) \r
-      printf("  -  ");\r
-    else\r
-      printf("%3.0f   ",tmp->fPhiRes*10000);\r
-    if (tmp->fZRes==RIDICULOUS) \r
-      printf("  -\n");\r
-    else\r
-      printf("%3.0f\n",tmp->fZRes*10000);\r
-  }\r
-}\r
-\r
-void KMCDetector::PlotLayout(Int_t plotDead) {\r
-  //\r
-  // Plots the detector layout in Front view\r
-  //\r
-\r
-  Double_t x0=0, y0=0;\r
-\r
-  TGraphErrors *gr = new TGraphErrors();\r
-  gr->SetPoint(0,0,0);\r
-  KMCLayer *lastLayer = (KMCLayer*)fLayers.At(fLayers.GetEntries()-1);  Double_t maxRad = lastLayer->fR;\r
-  gr->SetPointError(0,maxRad,maxRad);\r
-  gr->Draw("APE");\r
-  \r
-\r
-  KMCLayer *tmp = 0;\r
-  for (Int_t i = fLayers.GetEntries()-1; i>=0; i--) {\r
-    tmp = (KMCLayer*)fLayers.At(i);\r
-  \r
-\r
-    Double_t txtpos = tmp->fR;\r
-    if ((tmp->IsDead())) txtpos*=-1; //\r
-    TText *txt = new TText(x0,txtpos,tmp->GetName());\r
-    txt->SetTextSizePixels(5); txt->SetTextAlign(21);\r
-    if (!tmp->IsDead() || plotDead) txt->Draw();\r
-\r
-    TEllipse *layEl = new TEllipse(x0,y0,tmp->fR);\r
-    //  layEl->SetFillColor(5);\r
-    layEl->SetFillStyle(5001);\r
-    layEl->SetLineStyle(tmp->IsDead()+1); // dashed if not active\r
-    layEl->SetLineColor(4);\r
-    TString name(tmp->GetName());\r
-    if (!tmp->IsDead()) layEl->SetLineWidth(2);\r
-    if (name.Contains("tpc") )  layEl->SetLineColor(29);\r
-\r
-    if (!tmp->IsDead() || plotDead) layEl->Draw();\r
-  \r
-  }\r
-\r
-}\r
-\r
-\r
-\r
-void KMCDetector::AddTPC(Float_t phiResMean, Float_t zResMean, Int_t skip) {\r
-  //\r
-  // Emulates the TPC\r
-  // \r
-  // skip=1: Use every padrow, skip=2: Signal in every 2nd padrow \r
-\r
-\r
-  AddLayer((char*)"IFCtpc",   77.8,0.01367, 0); // Inner Field cage (RS: set correct xrho for eloss)\r
-  \r
-  // % Radiation Lengths ... Average per TPC row  (i.e. total/159 )\r
-  Float_t x2X0PerRow = 0.000036;\r
-  \r
-  Float_t tpcInnerRadialPitch  =    0.75 ;    // cm\r
-  Float_t tpcMiddleRadialPitch =    1.0  ;    // cm\r
-  Float_t tpcOuterRadialPitch  =    1.5  ;    // cm\r
-  //  Float_t tpcInnerPadWidth     =    0.4  ;    // cm\r
-  //  Float_t tpcMiddlePadWidth    =    0.6   ;   // cm\r
-  //  Float_t tpcOuterPadWidth     =    0.6   ;   // cm\r
-  Float_t innerRows            =   63 ;\r
-  Float_t middleRows           =   64  ;\r
-  Float_t outerRows            =   32  ;\r
-  Float_t tpcRows            =   (innerRows + middleRows + outerRows) ;\r
-  Float_t rowOneRadius         =   85.2  ;    // cm\r
-  Float_t row64Radius          =  135.1  ;    // cm\r
-  Float_t row128Radius         =  199.2  ;    // cm                       \r
\r
-  for ( Int_t k = 0 ; k < tpcRows ; k++ ) {\r
-    \r
-    Float_t rowRadius =0;\r
-    if (k<innerRows) \r
-      rowRadius =  rowOneRadius + k*tpcInnerRadialPitch ;\r
-    else if ( k>=innerRows && k<(innerRows+middleRows) )\r
-      rowRadius =  row64Radius + (k-innerRows+1)*tpcMiddleRadialPitch ;\r
-    else if (k>=(innerRows+middleRows) && k<tpcRows )\r
-      rowRadius = row128Radius + (k-innerRows-middleRows+1)*tpcOuterRadialPitch ;\r
-\r
-    if ( k%skip == 0 )\r
-      AddLayer(Form("tpc_%d",k),rowRadius,x2X0PerRow,0, phiResMean,zResMean);    \r
-    else \r
-      AddLayer(Form("tpc_%d",k),rowRadius,x2X0PerRow,0); // non "active" row\r
-    \r
-  \r
-  }\r
\r
-}\r
-\r
-void KMCDetector::RemoveTPC() {\r
-\r
-  // flag as dead, although resolution is ok ... makes live easier in the prints ... ;-)\r
-  KMCLayer *tmp = 0;\r
-  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {\r
-    tmp = (KMCLayer*)fLayers.At(i);  \r
-    TString name(tmp->GetName());\r
-    if (name.Contains("tpc")) { RemoveLayer((char*)name.Data()); i--; }\r
-  }\r
-  RemoveLayer((char*)"IFC");\r
-  \r
-}\r
-\r
-\r
-Double_t KMCDetector::ThetaMCS ( Double_t mass, Double_t x2X0, Double_t momentum ) const\r
-{\r
-  //\r
-  // returns the Multiple Couloumb scattering angle (compare PDG boolet, 2010, equ. 27.14)\r
-  //\r
-\r
-  Double_t beta  =  momentum / TMath::Sqrt(momentum*momentum+mass*mass)  ;\r
-  Double_t theta =  0.0 ;    // Momentum and mass in GeV\r
-  // if ( RadLength > 0 ) theta  =  0.0136 * TMath::Sqrt(RadLength) / ( beta * momentum );\r
-  if ( x2X0 > 0 ) theta  =  0.0136 * TMath::Sqrt(x2X0) / ( beta * momentum ) * (1+0.038*TMath::Log(x2X0)) ;\r
-  return (theta) ;\r
-}\r
-\r
-\r
-Double_t KMCDetector::ProbGoodHit ( Double_t radius, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) \r
-{\r
-  // Based on work by Howard Wieman: http://rnc.lbl.gov/~wieman/GhostTracks.htm \r
-  // and http://rnc.lbl.gov/~wieman/HitFinding2D.htm\r
-  // This is the probability of getting a good hit using 2D Gaussian distribution function and infinite search radius\r
-  Double_t sx, sy, goodHit ;\r
-  sx = 2 * TMath::Pi() *  searchRadiusRPhi * searchRadiusRPhi * HitDensity(radius) ;\r
-  sy = 2 * TMath::Pi() *  searchRadiusZ    * searchRadiusZ    * HitDensity(radius) ;\r
-  goodHit =  TMath::Sqrt(1./((1+sx)*(1+sy)))  ;\r
-  return ( goodHit ) ;\r
-}\r
-\r
-\r
-Double_t KMCDetector::ProbGoodChiSqHit ( Double_t radius, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) \r
-{\r
-  // Based on work by Victor Perevoztchikov and Howard Wieman: http://rnc.lbl.gov/~wieman/HitFinding2DXsq.htm\r
-  // This is the probability of getting a good hit using a Chi**2 search on a 2D Gaussian distribution function\r
-  Double_t sx, goodHit ;\r
-  sx = 2 * TMath::Pi() *  searchRadiusRPhi * searchRadiusZ * HitDensity(radius) ;\r
-  goodHit =  1./(1+sx) ;\r
-  return ( goodHit ) ;  \r
-}\r
-\r
-Double_t KMCDetector::ProbGoodChiSqPlusConfHit ( Double_t radius, Double_t leff, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) \r
-{\r
-  // Based on work by Ruben Shahoyen \r
-  // This is the probability of getting a good hit using a Chi**2 search on a 2D Gaussian distribution function\r
-  // Plus, in addition, taking a "confidence level" and the "layer efficiency" into account \r
-  // Following is correct for 2 DOF\r
-\r
-  Double_t c = -2 *TMath::Log(fConfLevel); // quantile at cut of confidence level\r
-  Double_t alpha = (1 + 2 * TMath::Pi() * HitDensity(radius) * searchRadiusRPhi * searchRadiusZ)/2; \r
-  Double_t goodHit = leff/(2*alpha) * (1 - TMath::Exp(-alpha*c));\r
-  return ( goodHit ) ;  \r
-}\r
-\r
-Double_t KMCDetector::ProbNullChiSqPlusConfHit ( Double_t radius, Double_t leff, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) \r
-{\r
-  // Based on work by Ruben Shahoyen \r
-  // This is the probability to not have any match to the track (see also :ProbGoodChiSqPlusConfHit:)\r
-\r
-  Double_t c = -2 *TMath::Log(fConfLevel); // quantile at cut of confidence level\r
-  Double_t alpha = (1 + 2 * TMath::Pi() * HitDensity(radius) * searchRadiusRPhi * searchRadiusZ)/2; \r
-  Double_t nullHit = (1-leff+fConfLevel*leff)*TMath::Exp(-c*(alpha-1./2));\r
-  return ( nullHit ) ;  \r
-}\r
-\r
-Double_t KMCDetector::HitDensity ( Double_t radius ) \r
-{\r
-  // Background (0-1) is included via 'OtherBackground' which multiplies the minBias rate by a scale factor.\r
-  // UPC electrons is a temporary kludge that is based on Kai Schweda's summary of Kai Hainken's MC results\r
-  // See K. Hencken et al. PRC 69, 054902 (2004) and PPT slides by Kai Schweda.\r
-  // Note that this function assumes we are working in CM and CM**2 [not meters].\r
-  // Based on work by Yan Lu 12/20/2006, all radii and densities in centimeters or cm**2.\r
-\r
-  //  Double_t MaxRadiusSlowDet = 0.1; //?   // Maximum radius for slow detectors.  Fast detectors \r
-                                        // and only fast detectors reside outside this radius.\r
-  Double_t arealDensity = 0 ;\r
-  if (radius<0.01) return 0;\r
-\r
-  if ( radius >= fMaxRadiusSlowDet ) \r
-    {\r
-      arealDensity  = OneEventHitDensity(fdNdEtaCent,radius)  ; // Fast detectors see central collision density (only)\r
-      arealDensity += OtherBackground*OneEventHitDensity(dNdEtaMinB,radius)  ;  // Increase density due to background \r
-    }\r
-\r
-  if (radius < fMaxRadiusSlowDet )\r
-    { // Note that IntegratedHitDensity will always be minB one event, or more, even if integration time => zero.\r
-      arealDensity  = OneEventHitDensity(fdNdEtaCent,radius) \r
-                   + IntegratedHitDensity(dNdEtaMinB,radius) \r
-                   + UpcHitDensity(radius) ;\r
-      arealDensity += OtherBackground*IntegratedHitDensity(dNdEtaMinB,radius) ;  \r
-      // Increase density due to background \r
-    } \r
-\r
-  return ( arealDensity ) ;  \r
-}\r
-\r
-\r
-double KMCDetector::OneEventHitDensity( Double_t multiplicity, Double_t radius ) const\r
-{\r
-  // This is for one event at the vertex.  No smearing.\r
-  double den   = multiplicity / (2.*TMath::Pi()*radius*radius) * fDensFactorEta ; // 2 eta ?\r
-  // note: surface of sphere is  '4*pi*r^2'\r
-  //       surface of cylinder is '2*pi*r* h' \r
-  return den ;\r
-} \r
-\r
-\r
-double KMCDetector::IntegratedHitDensity(Double_t multiplicity, Double_t radius)\r
-{ \r
-  // The integral of minBias events smeared over a gaussian vertex distribution.\r
-  // Based on work by Yan Lu 12/20/2006, all radii in centimeters.\r
-\r
-  Double_t zdcHz = Luminosity * 1.e-24 * CrossSectionMinB ;\r
-  Double_t den   = zdcHz * fIntegrationTime/1000. * multiplicity * Dist(0., radius) / (2.*TMath::Pi()*radius) ;\r
-\r
-  // Note that we do not allow the rate*time calculation to fall below one minB event at the vertex.\r
-  double dens1 = OneEventHitDensity(multiplicity,radius);\r
-  if ( den < dens1 )  den = dens1;\r
-\r
-  return den ;\r
-} \r
-\r
-\r
-double KMCDetector::UpcHitDensity(Double_t radius)\r
-{ \r
-  // QED electrons ...\r
-\r
-  Double_t mUPCelectrons ;                                 ;  \r
-  //  mUPCelectrons =  fLhcUPCscale * (1.23 - radius/6.5)      ;  // Fit to Kai Schweda summary tables at RHIC * 'scale' for LHC\r
-  mUPCelectrons = fLhcUPCscale*5456/(radius*radius)/dNdEtaMinB;      // Fit to 'Rossegger,Sadovsky'-Alice simulation\r
-  if ( mUPCelectrons < 0 ) mUPCelectrons =  0.0             ;  // UPC electrons fall off quickly and don't go to large R\r
-  mUPCelectrons *= IntegratedHitDensity(dNdEtaMinB,radius) ;  // UPCs increase Mulitiplicty ~ proportional to MinBias rate\r
-  mUPCelectrons *= UPCBackgroundMultiplier                 ;  // Allow for an external multiplier (eg 0-1) to turn off UPC\r
-\r
-  return mUPCelectrons ;\r
-} \r
-\r
-\r
-double KMCDetector::Dist(double z, double r)\r
-{\r
-  // Convolute dEta/dZ  distribution with assumed Gaussian of vertex z distribution\r
-  // Based on work by Howard Wieman http://rnc.lbl.gov/~wieman/HitDensityMeasuredLuminosity7.htm\r
-  // Based on work by Yan Lu 12/20/2006, all radii and Z location in centimeters.\r
-  Int_t    index  =  1     ;     // Start weight at 1 for Simpsons rule integration\r
-  Int_t    nsteps =  301   ;     // NSteps must be odd for Simpson's rule to work\r
-  double   dist   =  0.0   ;\r
-  double   dz0    =  ( 4*SigmaD - (-4)*SigmaD ) / (nsteps-1)  ;  //cm\r
-  double    z0    =  0.0   ;     //cm\r
-  for(int i=0; i<nsteps; i++){\r
-    if ( i == nsteps-1 ) index = 1 ;\r
-    z0 = -4*SigmaD + i*dz0 ;\r
-    dist += index * (dz0/3.) * (1/sqrt(2.*TMath::Pi())/SigmaD) * exp(-z0*z0/2./SigmaD/SigmaD) * \r
-      (1/sqrt((z-z0)*(z-z0) + r*r)) ;\r
-    if ( index != 4 ) index = 4; else index = 2 ;\r
-  }\r
-  return dist; \r
-}\r
-\r
-#define  PZero   0.861  // Momentum of back to back decay particles in the CM frame\r
-#define  EPiZero 0.872  // Energy of the pion from a D0 decay at rest\r
-#define  EKZero  0.993  // Energy of the Kaon from a D0 decay at rest\r
-\r
-Double_t KMCDetector::D0IntegratedEfficiency( Double_t pt, Double_t corrEfficiency[][20] ) const {\r
-  // Math from Ron Longacre.  Note hardwired energy to bin conversion for PtK and PtPi.\r
-\r
-  Double_t const1  =  pt / D0Mass ;\r
-  Double_t const2  =  TMath::Sqrt(pt*pt+D0Mass*D0Mass) / D0Mass ;\r
-  Double_t sum, ptPi, ptK ;\r
-  Double_t effp, effk ;\r
-\r
-  sum = 0.0 ;\r
-  for ( Int_t k = 0 ; k < 360 ; k++ )   {\r
-    \r
-    Double_t theta = k * TMath::Pi() / 180. ;\r
-    \r
-    ptPi = TMath::Sqrt( \r
-                      PZero*PZero*TMath::Cos(theta)*TMath::Cos(theta)*const2*const2 +\r
-                      const1*const1*EPiZero*EPiZero -\r
-                      2*PZero*TMath::Cos(theta)*const2*const1*EPiZero +\r
-                      PZero*PZero*TMath::Sin(theta)*TMath::Sin(theta)\r
-                      ) ;\r
-    \r
-    ptK = TMath::Sqrt( \r
-                     PZero*PZero*TMath::Cos(theta)*TMath::Cos(theta)*const2*const2 +\r
-                     const1*const1*EKZero*EKZero +\r
-                     2*PZero*TMath::Cos(theta)*const2*const1*EKZero +\r
-                     PZero*PZero*TMath::Sin(theta)*TMath::Sin(theta)\r
-                     ) ;\r
-\r
-    // JT Test Remove 100 MeV/c in pt to simulate eta!=0 decays\r
-    Int_t pionindex = (int)((ptPi-0.1)*100.0 - 65.0*TMath::Abs(fBFieldG)) ; \r
-    Int_t kaonindex = (int)((ptK -0.1)*100.0 - 65.0*TMath::Abs(fBFieldG)) ; \r
-      \r
-    if ( pionindex >= 20 ) pionindex = 399 ;\r
-    if ( pionindex >= 0 )   effp = corrEfficiency[0][pionindex] ;\r
-    if ( pionindex <  0 )   effp = (corrEfficiency[0][1]-corrEfficiency[0][0])*pionindex + corrEfficiency[0][0] ; // Extrapolate if reqd\r
-    if ( effp < 0 )         effp = 0 ;\r
-\r
-    if ( kaonindex >= 20 ) kaonindex = 399 ;\r
-    if ( kaonindex >= 0 )   effk = corrEfficiency[1][kaonindex] ;\r
-    if ( kaonindex <  0 )   effk = (corrEfficiency[1][1]-corrEfficiency[1][0])*kaonindex + corrEfficiency[1][0] ; // Extrapolate if reqd\r
-    if ( effk < 0 )         effk = 0 ;\r
-\r
-    // Note that we assume that the Kaon Decay efficiency has already been inlcuded in the kaon efficiency used here.\r
-      \r
-    sum += effp * effk ;\r
\r
-  }    \r
-  \r
-  Double_t mean =sum/360; \r
-  return mean ;\r
-  \r
-}\r
-\r
-KMCProbe* KMCDetector::PrepareKalmanTrack(double pt, double lambda, double mass, int charge, double phi, double x,double y, double z)\r
-{\r
-  // Prepare trackable Kalman track at the farthest position\r
-  //\r
-  // Set track parameters\r
-  // Assume track started at (0,0,0) and shoots out on the X axis, and B field is on the Z axis\r
-  fProbe.Reset();\r
-  fProbe.SetMass(mass);\r
-  KMCProbe* probe = new KMCProbe(fProbe);\r
-  double *trPars = (double*)probe->GetParameter();\r
-  double *trCov  = (double*)probe->GetCovariance();\r
-  double xyz[3] = {x,y,z};\r
-  probe->Global2LocalPosition(xyz,phi);\r
-  probe->Set(xyz[0],phi,trPars,trCov);\r
-  trPars[KMCProbe::kY] = xyz[1];\r
-  trPars[KMCProbe::kZ] = xyz[2];\r
-  trPars[KMCProbe::kSnp] = 0;                       //            track along X axis at the vertex\r
-  trPars[KMCProbe::kTgl] = TMath::Tan(lambda);                // dip\r
-  trPars[KMCProbe::kPtI] = charge/pt;               //            q/pt      \r
-  //\r
-  // put tiny errors to propagate to the outer-most radius\r
-  trCov[KMCProbe::kY2] = trCov[KMCProbe::kZ2] = trCov[KMCProbe::kSnp2] = trCov[KMCProbe::kTgl2] = trCov[KMCProbe::kPtI2] = 1e-20;\r
-  fProbe = *probe;  // store original track\r
-  //\r
-  // propagate to last layer\r
-  fLastActiveLayerTracked = 0;\r
-  for (Int_t j=0; j<=fLastActiveLayer; j++) {\r
-    KMCLayer* lr = GetLayer(j);\r
-    lr->Reset();\r
-    //\r
-    if (!PropagateToLayer(probe,lr,1)) break;\r
-    if (!probe->CorrectForMeanMaterial(lr, kFALSE)) break;\r
-    //\r
-    lr->fClCorr.Set(probe->GetY(),probe->GetZ(), probe->GetX(), probe->GetAlpha());\r
-    if (!lr->IsDead()) fLastActiveLayerTracked = j;\r
-  }\r
-  probe->ResetCovMat();// reset cov.matrix\r
-  printf("Last active layer trracked: %d (out of %d)\n",fLastActiveLayerTracked,fLastActiveLayer);\r
-  //\r
-  return probe;\r
-}\r
-\r
-\r
-\r
-TGraph * KMCDetector::GetGraphMomentumResolution(Int_t color, Int_t linewidth) {\r
-  //\r
-  // returns the momentum resolution \r
-  //\r
-  \r
-  TGraph *graph = new TGraph(20, fTransMomenta, fMomentumRes);\r
-  graph->SetTitle("Momentum Resolution .vs. Pt" ) ;\r
-  //  graph->GetXaxis()->SetRangeUser(0.,5.0) ;\r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->SetTitle("Momentum Resolution (%)") ;\r
-  graph->GetYaxis()->CenterTitle();\r
-\r
-  graph->SetMaximum(20) ;\r
-  graph->SetMinimum(0.1) ;\r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  graph->SetLineWidth(linewidth);\r
-\r
-  return graph;\r
-\r
-}\r
-\r
-TGraph * KMCDetector::GetGraphPointingResolution(Int_t axis, Int_t color, Int_t linewidth) {\r
\r
-  // Returns the pointing resolution\r
-  // axis = 0 ... rphi pointing resolution\r
-  // axis = 1 ... z pointing resolution\r
-  //\r
-\r
-  TGraph * graph =  0;\r
-\r
-  if (axis==0) {\r
-    graph = new TGraph ( 20, fTransMomenta, fResolutionRPhi ) ;\r
-    graph->SetTitle("R-#phi Pointing Resolution .vs. Pt" ) ;\r
-    graph->GetYaxis()->SetTitle("R-#phi Pointing Resolution (#mum)") ;\r
-  } else {\r
-    graph =  new TGraph ( 20, fTransMomenta, fResolutionZ ) ;\r
-    graph->SetTitle("Z Pointing Resolution .vs. Pt" ) ;\r
-    graph->GetYaxis()->SetTitle("Z Pointing Resolution (#mum)") ;\r
-  }\r
-  \r
-  graph->SetMinimum(1) ;\r
-  graph->SetMaximum(300.1) ;\r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->CenterTitle();\r
-  \r
-  graph->SetLineWidth(linewidth);\r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  \r
-  return graph;\r
-\r
-}\r
-\r
-\r
-TGraph * KMCDetector::GetGraphPointingResolutionTeleEqu(Int_t axis,Int_t color, Int_t linewidth) {\r
-  //\r
-  // returns the Pointing resolution (accoring to Telescope equation)\r
-  // axis =0 ... in rphi\r
-  // axis =1 ... in z\r
-  //\r
-  \r
-  Double_t resolution[20];\r
-\r
-  Double_t layerResolution[2];\r
-  Double_t layerRadius[2];\r
-  Double_t layerThickness[2];\r
-\r
-  Int_t count =0; // search two first active layers\r
-  printf("Telescope equation for layers:  ");\r
-  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {\r
-    KMCLayer *l = (KMCLayer*)fLayers.At(i);\r
-    if (!l->IsDead() && l->fR>0) {\r
-      layerRadius[count]     = l->fR;\r
-      layerThickness[count]  = l->fx2X0;\r
-      if (axis==0) {\r
-       layerResolution[count] = l->fPhiRes;\r
-      } else {\r
-       layerResolution[count] = l->fZRes;\r
-      }\r
-      printf("%s, ",l->GetName());\r
-      count++;\r
-    }\r
-    if (count>=2) break;       \r
-  }\r
-  printf("\n");\r
-\r
-  Double_t pt, momentum, thickness,aMCS ;\r
-  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); \r
-\r
-  for ( Int_t i = 0 ; i < 20 ; i++ ) { \r
-    // Reference data as if first two layers were acting all alone \r
-    pt  =  fTransMomenta[i]  ;\r
-    momentum = pt / TMath::Cos(lambda)   ;  // Total momentum\r
-    resolution[i] =  layerResolution[0]*layerResolution[0]*layerRadius[1]*layerRadius[1] \r
-      +  layerResolution[1]*layerResolution[1]*layerRadius[0]*layerRadius[0] ;\r
-    resolution[i] /= ( layerRadius[1] - layerRadius[0] ) * ( layerRadius[1] - layerRadius[0] ) ;\r
-    thickness = layerThickness[0] / TMath::Sin(TMath::Pi()/2 - lambda) ;\r
-    aMCS = ThetaMCS(fParticleMass, thickness, momentum) ;\r
-    resolution[i] += layerRadius[0]*layerRadius[0]*aMCS*aMCS ;\r
-    resolution[i] =  TMath::Sqrt(resolution[i]) * 10000.0 ;  // result in microns\r
-  }\r
-\r
-\r
-\r
-  TGraph* graph = new TGraph ( 20, fTransMomenta, resolution ) ;\r
-   \r
-  if (axis==0) {\r
-    graph->SetTitle("RPhi Pointing Resolution .vs. Pt" ) ;\r
-    graph->GetYaxis()->SetTitle("RPhi Pointing Resolution (#mum) ") ;\r
-  } else {\r
-    graph->SetTitle("Z Pointing Resolution .vs. Pt" ) ;\r
-    graph->GetYaxis()->SetTitle("Z Pointing Resolution (#mum) ") ;\r
-  }\r
-  graph->SetMinimum(1) ;\r
-  graph->SetMaximum(300.1) ;\r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->CenterTitle();\r
-  \r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  graph->SetLineStyle(kDashed);\r
-  graph->SetLineWidth(linewidth);\r
-\r
-  return graph;\r
-\r
-}\r
-\r
-TGraph * KMCDetector::GetGraphRecoEfficiency(Int_t particle,Int_t color, Int_t linewidth) {\r
-  //\r
-  // particle = 0 ... choosen particle (setted particleMass)\r
-  // particle = 1 ... Pion\r
-  // particle = 2 ... Kaon\r
-  // particle = 3 ... D0\r
-  //\r
-  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); \r
-  \r
-  Double_t particleEfficiency[20]; // with chosen particle mass\r
-  Double_t kaonEfficiency[20], pionEfficiency[20], d0efficiency[20]; \r
-  Double_t partEfficiency[2][20];\r
-  \r
-  if (particle != 0) {\r
-    // resulting Pion and Kaon efficiency scaled with overall efficiency\r
-    Double_t doNotDecayFactor;\r
-    for ( Int_t massloop = 0 ; massloop < 2 ; massloop++) { //0-pion, 1-kaon\r
-      \r
-      for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-       // JT Test Let the kaon decay.  If it decays inside the TPC ... then it is gone; for all decays < 130 cm.\r
-       Double_t momentum = fTransMomenta[j] / TMath::Cos(lambda)           ;  // Total momentum at average rapidity\r
-       if ( massloop == 1 ) { // KAON\r
-         doNotDecayFactor  = TMath::Exp(-130/(371*momentum/KaonMass)) ;  // Decay length for kaon is 371 cm.\r
-         kaonEfficiency[j] = fEfficiency[1][j] * AcceptanceOfTpcAndSi*doNotDecayFactor ;\r
-       } else { // PION\r
-         doNotDecayFactor = 1.0 ;\r
-         pionEfficiency[j] = fEfficiency[0][j] * AcceptanceOfTpcAndSi*doNotDecayFactor ;       \r
-       }\r
-       partEfficiency[0][j] = pionEfficiency[j];\r
-       partEfficiency[1][j] = kaonEfficiency[j];\r
-      }      \r
-    }\r
-    \r
-    // resulting estimate of the D0 efficiency\r
-    for ( Int_t j = 0 ; j < 20 ; j++ ) {\r
-      d0efficiency[j] = D0IntegratedEfficiency(fTransMomenta[j],partEfficiency);\r
-    }\r
-  } else { \r
-    for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-      particleEfficiency[j] = fEfficiency[2][j]* AcceptanceOfTpcAndSi;\r
-      // NOTE: Decay factor (see kaon) should be included to be realiable\r
-    }\r
-  }\r
-\r
-  for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-    pionEfficiency[j]     *= 100;\r
-    kaonEfficiency[j]     *= 100;\r
-    d0efficiency[j]       *= 100;\r
-    particleEfficiency[j] *= 100;\r
-  }\r
\r
-  TGraph * graph =  0;\r
-  if (particle==0) {\r
-    graph = new TGraph ( 20, fTransMomenta, particleEfficiency ) ; // choosen mass\r
-    graph->SetLineWidth(1);\r
-  }  else if (particle==1) {\r
-    graph = new TGraph ( 20, fTransMomenta, pionEfficiency ) ;\r
-    graph->SetLineWidth(1);\r
-  }  else if (particle ==2) {\r
-    graph = new TGraph ( 20, fTransMomenta, kaonEfficiency ) ;\r
-    graph->SetLineWidth(1);\r
-  }  else if (particle ==3) {\r
-    graph = new TGraph ( 20, fTransMomenta, d0efficiency ) ;\r
-    graph->SetLineStyle(kDashed);\r
-  } else \r
-    return 0;\r
-\r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->SetTitle("Efficiency (%)") ;\r
-  graph->GetYaxis()->CenterTitle();\r
-         \r
-  graph->SetMinimum(0.01) ; \r
-  graph->SetMaximum(100)  ; \r
-\r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  graph->SetLineWidth(linewidth);\r
-\r
-  return graph;\r
-}\r
-\r
-TGraph * KMCDetector::GetGraphRecoFakes(Int_t particle,Int_t color, Int_t linewidth) {\r
-  //\r
-  // particle = 0 ... choosen particle (setted particleMass)\r
-  // particle = 1 ... Pion\r
-  // particle = 2 ... Kaon\r
-  //\r
-\r
-  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); \r
-  \r
-  Double_t particleFake[20]; // with chosen particle mass\r
-  Double_t kaonFake[20], pionFake[20];\r
-  Double_t partFake[2][20];\r
-  \r
-  if (particle != 0) {\r
-    // resulting Pion and Kaon efficiency scaled with overall efficiency\r
-    Double_t doNotDecayFactor;\r
-    for ( Int_t massloop = 0 ; massloop < 2 ; massloop++) { //0-pion, 1-kaon\r
-      \r
-      for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-       // JT Test Let the kaon decay.  If it decays inside the TPC ... then it is gone; for all decays < 130 cm.\r
-       Double_t momentum = fTransMomenta[j] / TMath::Cos(lambda)           ;  // Total momentum at average rapidity\r
-       if ( massloop == 1 ) { // KAON\r
-         doNotDecayFactor  = TMath::Exp(-130/(371*momentum/KaonMass)) ;  // Decay length for kaon is 371 cm.\r
-         kaonFake[j] = fFake[1][j] /( doNotDecayFactor) ;\r
-       } else { // PION\r
-         pionFake[j] = fFake[0][j] ;   \r
-       }\r
-       partFake[0][j] = pionFake[j];\r
-       partFake[1][j] = kaonFake[j];\r
-      }      \r
-    }\r
-    \r
-  } else { \r
-    for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-      particleFake[j] = fFake[2][j];\r
-      // NOTE: Decay factor (see kaon) should be included to be realiable\r
-    }\r
-  }\r
-\r
-  for ( Int_t j = 0 ; j < 20 ; j++ ) { \r
-    pionFake[j]     *= 100;\r
-    kaonFake[j]     *= 100;\r
-    particleFake[j] *= 100;\r
-  }\r
\r
-  TGraph * graph =  0;\r
-  if (particle==0) {\r
-    graph = new TGraph ( 20, fTransMomenta, particleFake ) ; // choosen mass\r
-    graph->SetLineWidth(1);\r
-  }  else if (particle==1) {\r
-    graph = new TGraph ( 20, fTransMomenta, pionFake ) ;\r
-    graph->SetLineWidth(1);\r
-  }  else if (particle ==2) {\r
-    graph = new TGraph ( 20, fTransMomenta, kaonFake ) ;\r
-    graph->SetLineWidth(1);\r
-  } \r
-  \r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->SetTitle("Fake (%)") ;\r
-  graph->GetYaxis()->CenterTitle();\r
-         \r
-  graph->SetMinimum(0.01) ; \r
-  graph->SetMaximum(100)  ; \r
-\r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  graph->SetLineWidth(linewidth);\r
-\r
-  return graph;\r
-}\r
-\r
-\r
-TGraph* KMCDetector::GetGraphImpactParam(Int_t mode, Int_t axis, Int_t color, Int_t linewidth) {\r
-  //\r
-  // returns the Impact Parameter d0 (convolution of pointing resolution and vtx resolution)\r
-  // mode 0: impact parameter (convolution of pointing and vertex resolution)\r
-  // mode 1: pointing resolution\r
-  // mode 2: vtx resolution \r
-  \r
-  \r
-  TGraph *graph = new TGraph();\r
-\r
-  //  TFormula vtxResRPhi("vtxRes","50-2*x"); // 50 microns at pt=0, 15 microns at pt =20 ?\r
-  TFormula vtxResRPhi("vtxRes","35/(x+1)+10"); // \r
-  TFormula vtxResZ("vtxResZ","600/(x+6)+10"); // \r
-    \r
-  TGraph *trackRes = GetGraphPointingResolution(axis,1);\r
-  Double_t *pt = trackRes->GetX();\r
-  Double_t *trRes = trackRes->GetY();\r
-  for (Int_t ip =0; ip<trackRes->GetN(); ip++) {\r
-    Double_t vtxRes = 0;\r
-    if (axis==0) \r
-      vtxRes = vtxResRPhi.Eval(pt[ip]);\r
-    else \r
-      vtxRes = vtxResZ.Eval(pt[ip]);\r
-    \r
-    if (mode==0)\r
-      graph->SetPoint(ip,pt[ip],TMath::Sqrt(vtxRes*vtxRes+trRes[ip]*trRes[ip]));\r
-    else if (mode ==1)\r
-      graph->SetPoint(ip,pt[ip],trRes[ip]);\r
-    else\r
-      graph->SetPoint(ip,pt[ip],vtxRes);\r
-  }\r
-  \r
-  graph->SetTitle("d_{0} r#phi resolution .vs. Pt" ) ;\r
-  graph->GetYaxis()->SetTitle("d_{0} r#phi resolution (#mum)") ;\r
-  \r
-  graph->SetMinimum(1) ;\r
-  graph->SetMaximum(300.1) ;\r
-  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;\r
-  graph->GetXaxis()->CenterTitle();\r
-  graph->GetXaxis()->SetNoExponent(1) ;\r
-  graph->GetXaxis()->SetMoreLogLabels(1) ;\r
-  graph->GetYaxis()->CenterTitle();\r
-  \r
-  graph->SetLineColor(color);\r
-  graph->SetMarkerColor(color);\r
-  graph->SetLineWidth(linewidth);\r
-\r
-  return graph;\r
-\r
-}\r
-\r
-TGraph* KMCDetector::GetGraph(Int_t number, Int_t color, Int_t linewidth) {\r
-  // \r
-  // returns graph according to the number\r
-  //\r
-  switch(number) {\r
-  case 1:\r
-    return GetGraphPointingResolution(0,color, linewidth); // dr\r
-  case 2:\r
-    return GetGraphPointingResolution(1,color, linewidth); // dz\r
-  case 3:\r
-    return GetGraphPointingResolutionTeleEqu(0,color, linewidth); // dr - tele\r
-  case 4:\r
-    return GetGraphPointingResolutionTeleEqu(1,color, linewidth); // dz - tele\r
-  case 5:\r
-    return GetGraphMomentumResolution(color, linewidth); // pt resolution\r
-  case 10:\r
-    return GetGraphRecoEfficiency(0, color, linewidth);  // tracked particle\r
-  case 11:\r
-    return GetGraphRecoEfficiency(1, color, linewidth);  // eff. pion\r
-  case 12:\r
-    return GetGraphRecoEfficiency(2, color, linewidth);  // eff. kaon\r
-  case 13: \r
-    return GetGraphRecoEfficiency(3, color, linewidth);  // eff. D0\r
-  case 15:\r
-    return GetGraphRecoFakes(0, color, linewidth);  // Fake tracked particle\r
-  case 16:\r
-    return GetGraphRecoFakes(1, color, linewidth);  // Fake pion\r
-  case 17:\r
-    return GetGraphRecoFakes(2, color, linewidth);  // Fake kaon\r
-  default:\r
-    printf(" Error: chosen graph number not valid\n");\r
-  }\r
-  return 0;\r
-\r
-}\r
-\r
-void KMCDetector::MakeAliceAllNew(Bool_t flagTPC,Bool_t flagMon, int setVer) {\r
-  \r
-  // All New configuration with X0 = 0.3 and resolution = 4 microns\r
-  \r
-  AddLayer((char*)"bpipe_its",2.0,0.0022, 0.092); // beam pipe, 0.5 mm Be\r
-  AddLayer((char*)"vertex_its",     0,     0); // dummy vertex for matrix calculation\r
-  if (fgVtxConstraint[0]>0 && fgVtxConstraint[1]>0) {\r
-    printf("vertex will work as constraint: %.4f %.4f\n",fgVtxConstraint[0],fgVtxConstraint[1]);\r
-    SetResolution((char*)"vertex_its",fgVtxConstraint[0],fgVtxConstraint[1]);\r
-  }\r
-  //\r
-  // new ideal Pixel properties?\r
-  Double_t x0     = 0.0050;\r
-  Double_t resRPhi = 0.0006;\r
-  Double_t resZ   = 0.0006;\r
-  Double_t xrho = 0.0116;  // assume 0.5mm of silicon for eloss\r
-  //\r
-  if (flagMon) {\r
-    x0 *= 3./5.;\r
-    xrho *=3./5.;\r
-    resRPhi = 0.0004;\r
-    resZ   = 0.0004;\r
-  }\r
-\r
-  double sclD = 1;\r
-  double sclZ = 1;\r
-\r
-  // default all new  \r
-  if (setVer<=0) {\r
-    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); \r
-  }\r
-  else if (setVer==1) {\r
-    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its2",  2.8 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its3",  3.6 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its4", 20.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its5", 22.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its6", 43.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its7", 43.6 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    //\r
-    /*\r
-    UInt_t patt[] = {\r
-      KMCTrackSummary::Bits(1,1,1),\r
-      KMCTrackSummary::Bits(0,0,0,1,1),\r
-      KMCTrackSummary::Bits(0,0,0,0,0,1,1)\r
-    };\r
-    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));\r
-    */\r
-  }\r
-  else if (setVer==2) {\r
-    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its1a", 2.8 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its2",  3.6 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its2a", 4.2 ,  x0, xrho, resRPhi, resZ); \r
-    AddLayer((char*)"its3", 20.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its4", 22.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its5", 33.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its6", 43.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    AddLayer((char*)"its7", 43.6 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); \r
-    //\r
-    /*\r
-    UInt_t patt[] = {\r
-      KMCTrackSummary::Bits(1,1,1,1),\r
-      KMCTrackSummary::Bits(0,0,0,0,1,1),\r
-      KMCTrackSummary::Bits(0,0,0,0,0,0,1,1,1)\r
-    };\r
-    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));\r
-    */\r
-  }\r
-   /*\r
-  // last 2 layers strips\r
-  double resRPStr=0.0020, resZStr = 0.0830;\r
-  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPStr, resZStr); \r
-  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPStr, resZStr); \r
-   */\r
-  //*/\r
-  /*\r
-  // resolution scaled with R as res(2.2) * R/2.2\r
-  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); \r
-  KMCLayer* lr0 = 0;\r
-  for (int i=0;i<GetNActiveITSLayers();i++) {\r
-    KMCLayer *lr = GetActiveLayer(i);\r
-    if (lr->IsVertex()) continue;\r
-    if (lr0==0) {\r
-      lr0=lr; \r
-      //  continue;\r
-    }\r
-    double scl = 5*lr->GetRadius()/lr0->GetRadius();\r
-    SetResolution((char*)lr->GetName(), resRPhi*scl, resZ*scl*4);\r
-  }\r
-  */\r
-  /*\r
-  // 1st 2 layers double\r
-  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its1a",  2.8 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its2a",  4.2 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its3a",  6.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); \r
-  */\r
-  /*\r
-  // last 4 layers doubled\r
-  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its4a", 12.8 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its5a", 23.9 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its6a", 40.0 ,  x0, xrho, resRPhi, resZ); \r
-\r
-  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its7a", 43.4 ,  x0, xrho, resRPhi, resZ); \r
-  */\r
-\r
-  /* //last 3 lr together \r
-  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its5", 42.2 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its6", 42.6 ,  x0, xrho, resRPhi, resZ); \r
-  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); \r
-  */\r
-  if (flagTPC) {\r
-    AddTPC(0.1,0.1);                        // TPC\r
-  }\r
-  PrintLayout();\r
-}\r
-\r
-void KMCDetector::MakeAliceCurrent(Bool_t flagTPC, Int_t AlignResiduals) {\r
-\r
-  // Numbers taken from \r
-  // 2010 JINST 5 P03003 - Alignment of the ALICE Inner Tracking System with cosmic-ray tracks\r
-  // number for misalingment: private communication with Andrea Dainese\r
-\r
-  //  1.48e-01, 2.48e-01,2.57e-01, 1.34e-01, 3.34e-01,3.50e-01, 2.22e-01, 2.38e-01,2.25e-01};\r
-\r
-  AddLayer((char*)"vertex_its",     0,     0); // dummy vertex for matrix calculation\r
-  if (fgVtxConstraint[0]>0 && fgVtxConstraint[1]>0) {\r
-    printf("vertex will work as constraint: %.4f %.4f",fgVtxConstraint[0],fgVtxConstraint[1]);\r
-    SetResolution((char*)"vertex_its",fgVtxConstraint[0],fgVtxConstraint[1]);\r
-  }\r
-  //\r
-  AddLayer((char*)"bpipe_its",2.94,0.0022, 1.48e-01); // beam pipe\r
-  AddLayer((char*)"tshld1_its",11.5,0.0065, 1.34e-01); // Thermal shield  // 1.3% /2\r
-  AddLayer((char*)"tshld2_its",31.0,0.0108, 2.22e-01); // Thermal shield  // 1.3% /2\r
-  //\r
-  if (flagTPC) {\r
-    AddTPC(0.1,0.1);                        // TPC\r
-  }\r
-  // Adding the ITS - current configuration\r
-  \r
-  if (AlignResiduals==0) {\r
-    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, 0.0012, 0.0130);\r
-    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, 0.0012, 0.0130);\r
-    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, 0.0035, 0.0025);\r
-    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, 0.0035, 0.0025);\r
-    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, 0.0020, 0.0830);\r
-    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, 0.0020, 0.0830);\r
-    /*\r
-    UInt_t patt[] = {\r
-      KMCTrackSummary::Bits(1,1),\r
-      KMCTrackSummary::Bits(0,0,1,1),\r
-      KMCTrackSummary::Bits(0,0,0,0,1,1)\r
-    };\r
-    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));\r
-    */\r
-  } else if (AlignResiduals==1) {\r
-\r
-    // tracking errors ...\r
-    // (Additional systematic errors due to misalignments) ... \r
-    // itsRecoParam->SetClusterMisalErrorYBOn(0.0010,0.0030,0.0500,0.0500,0.0020,0.0020);  // [cm]\r
-    // itsRecoParam->SetClusterMisalErrorZBOn(0.0050,0.0050,0.0050,0.0050,0.1000,0.1000);\r
-\r
-    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0010*0.0010), \r
-            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));\r
-    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0030*0.0030),\r
-            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));\r
-    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0100*0.0100),\r
-            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));\r
-    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0100*0.0100),\r
-            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));\r
-    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020), \r
-            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));\r
-    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020),\r
-            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));   \r
-    \r
-  } else if (AlignResiduals==2) {\r
-\r
-    \r
-    // tracking errors ... PLUS ... module misalignment\r
-    \r
-    // itsRecoParam->SetClusterMisalErrorYBOn(0.0010,0.0030,0.0500,0.0500,0.0020,0.0020);  // [cm]\r
-    // itsRecoParam->SetClusterMisalErrorZBOn(0.0050,0.0050,0.0050,0.0050,0.1000,0.1000);\r
-    \r
-    //  the ITS modules are misalignment with small gaussian smearings with\r
-    //  sigmarphi ~ 8, 10, 10 micron in SPD, SDD, SSD\r
-    \r
-    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0010*0.0010+0.0008*0.0008), \r
-            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));\r
-    AddLayer((char*)"spd2_ots", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0030*0.0030+0.0008*0.0008),\r
-            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));\r
-    AddLayer((char*)"sdd1_ots",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0500*0.0500+0.0010*0.0010),\r
-            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));\r
-    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0500*0.0500+0.0010*0.0010),\r
-            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));\r
-    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020+0.0010*0.0010), \r
-            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));\r
-    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020+0.0010*0.0010),\r
-            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000)); \r
-\r
-  } else {\r
-      \r
-      //  the ITS modules are misalignment with small gaussian smearings with\r
-      //  sigmarphi ~ 8, 10, 10 micron in SPD, SDD, SSD\r
-      //  unknown in Z ????\r
-\r
-    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0008*0.0008), \r
-            TMath::Sqrt(0.0130*0.0130+0.000*0.000));\r
-    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0008*0.0008),\r
-            TMath::Sqrt(0.0130*0.0130+0.000*0.000));\r
-    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0010*0.0010),\r
-            TMath::Sqrt(0.0025*0.0025+0.000*0.000));\r
-    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0010*0.0010),\r
-            TMath::Sqrt(0.0025*0.0025+0.000*0.000));\r
-    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0010*0.0010), \r
-            TMath::Sqrt(0.0830*0.0830+0.000*0.000));\r
-    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0010*0.0010),\r
-            TMath::Sqrt(0.0830*0.0830+0.000*0.000));       \r
-  }\r
-  \r
-}\r
-\r
-\r
-void KMCDetector::MakeStandardPlots(Bool_t add, Int_t color, Int_t linewidth,Bool_t onlyPionEff) {\r
-  //\r
-  // Produces the standard performace plots\r
-  //\r
\r
-  if (!add) {\r
-\r
-    TCanvas *c1 = new TCanvas("c1","c1");//,100,100,500,500);  \r
-    c1->Divide(2,2);\r
-    \r
-    c1->cd(1);  gPad->SetGridx();   gPad->SetGridy(); \r
-    gPad->SetLogx(); \r
-    TGraph *eff = GetGraphRecoEfficiency(1,color,linewidth);\r
-    eff->SetTitle("Efficiencies");\r
-    eff->Draw("AL");\r
-    if (!onlyPionEff) {\r
-      GetGraphRecoEfficiency(2,color,linewidth)->Draw("L");\r
-      GetGraphRecoEfficiency(3,color,linewidth)->Draw("L");\r
-    }\r
-    c1->cd(2); gPad->SetGridx();   gPad->SetGridy(); \r
-    gPad->SetLogy();  gPad->SetLogx(); \r
-    GetGraphMomentumResolution(color,linewidth)->Draw("AL");\r
-    \r
-    c1->cd(3); gPad->SetGridx();   gPad->SetGridy(); \r
-    gPad->SetLogx(); \r
-    GetGraphPointingResolution(0,color,linewidth)->Draw("AL");\r
-    \r
-    c1->cd(4); gPad->SetGridx();   gPad->SetGridy(); \r
-    gPad->SetLogx(); \r
-    GetGraphPointingResolution(1,color,linewidth)->Draw("AL");\r
-\r
-  } else {\r
-\r
-    TVirtualPad *c1 = gPad->GetMother();\r
-\r
-    c1->cd(1);\r
-    GetGraphRecoEfficiency(1,color,linewidth)->Draw("L");\r
-    if (!onlyPionEff) {\r
-      GetGraphRecoEfficiency(2,color,linewidth)->Draw("L");\r
-      GetGraphRecoEfficiency(3,color,linewidth)->Draw("L");\r
-    }\r
-    c1->cd(2); GetGraphMomentumResolution(color,linewidth)->Draw("L");\r
-    \r
-    c1->cd(3); GetGraphPointingResolution(0,color,linewidth)->Draw("L");\r
-    \r
-    c1->cd(4); GetGraphPointingResolution(1,color,linewidth)->Draw("L");\r
-    \r
-  }\r
-\r
-}\r
-\r
-void KMCDetector::ApplyMS(KMCProbe* trc, double x2X0) const\r
-{\r
-  // simulate random modification of track params due to the MS\r
-  if (x2X0<=0) return;\r
-  double alpha = trc->GetAlpha(); // store original alpha\r
-  double mass = trc->GetMass();\r
-  //\r
-  double snp = trc->GetSnp();\r
-  double dip = trc->GetTgl();\r
-  Double_t angle=TMath::Sqrt((1.+ dip*dip)/((1-snp)*(1.+snp)));\r
-  x2X0 *= angle;\r
-  //\r
-  static double covCorr[15],covDum[21]={0};\r
-  static double mom[3],pos[3];\r
-  double *cov = (double*) trc->GetCovariance();\r
-  memcpy(covCorr,cov,15*sizeof(double));\r
-  trc->GetXYZ(pos);\r
-  trc->GetPxPyPz(mom);\r
-  double pt2 = mom[0]*mom[0]+mom[1]*mom[1];\r
-  double pt = TMath::Sqrt(pt2);\r
-  double ptot2 = pt2 + mom[2]*mom[2];\r
-  double ptot  = TMath::Sqrt(ptot2);\r
-  double beta = ptot/TMath::Sqrt(ptot2 + mass*mass);\r
-  double sigth = TMath::Sqrt(x2X0)*0.014/(ptot*beta);\r
-  //\r
-  // a la geant\r
-  double phiSC = gRandom->Rndm()*TMath::Pi();\r
-  double thtSC = gRandom->Gaus(0,1.4142*sigth);\r
-  //  printf("MS phi: %+.5f tht: %+.5f\n",phiSC,thtSC);\r
-  double sn = TMath::Sin(thtSC);\r
-  double dx = sn*TMath::Sin(phiSC);\r
-  double dy = sn*TMath::Cos(phiSC);  \r
-  double dz = TMath::Cos(thtSC);\r
-  double v[3];\r
-  //  printf("Before: %+.3e %+.3e %+.3e | MS: %+.3e %+.3e\n",mom[0],mom[1],mom[2],thtSC,phiSC);\r
-  for (int i=3;i--;) mom[i] /= ptot;\r
-  double vmm = TMath::Sqrt(mom[0]*mom[0]+mom[1]*mom[1]);\r
-  if (!IsZero(pt)) {\r
-    double pd1 = mom[0]/vmm;\r
-    double pd2 = mom[1]/vmm;\r
-    v[0] = pd1*mom[2]*dx - pd2*dy + mom[0]*dz;\r
-    v[1] = pd2*mom[2]*dx + pd1*dy + mom[1]*dz;\r
-    v[2] = -vmm*dx                + mom[2]*dz;\r
-  }\r
-  else {\r
-    v[0] = dx;\r
-    v[1] = dy;\r
-    v[2] = dz*TMath::Sign(1.,mom[2]);\r
-  }\r
-  double nrm = TMath::Sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);\r
-  //  printf("before :%+e %+e %+e  || %+e %+e %+e %+e\n",mom[0],mom[1],mom[2],  sigth, x2X0, pt, beta);\r
-  //  trc->Print();\r
-  // direction cosines -> p\r
-  for (int i=3;i--;) mom[i] = ptot*v[i]/nrm;\r
-  //  printf("After : %+.3e %+.3e %+.3e\n",mom[0],mom[1],mom[2]);\r
-  trc->Set(pos,mom,covDum,trc->Charge());\r
-  //\r
-  trc->Rotate(alpha);\r
-  memcpy(cov,covCorr,15*sizeof(double));\r
-  //\r
-}\r
-\r
-//________________________________________________________________________________\r
-Bool_t KMCDetector::TransportKalmanTrackWithMS(KMCProbe *probTr, int maxLr) const\r
-{\r
-  // Transport track till layer maxLr, applying random MS\r
-  //\r
-  for (Int_t j=0; j<maxLr; j++) {\r
-    KMCLayer* lr0 = (KMCLayer*)fLayers.At(j);\r
-    KMCLayer* lr  = (KMCLayer*)fLayers.At(j+1);\r
-    if (!lr0->IsVertex()) {\r
-      ApplyMS(probTr,lr0->fx2X0); // apply MS\r
-      if (!probTr->CorrectForMeanMaterial(lr0,kFALSE)) return kFALSE; \r
-    }\r
-    //\r
-    if (!PropagateToLayer(probTr,lr,1)) return kFALSE;\r
-    // store randomized cluster local coordinates and phi\r
-    lr->ResetBgClusters();\r
-    double rz,ry;\r
-    gRandom->Rannor(rz,ry);\r
-    lr->GetMCCluster()->Set(probTr->GetY()+ry*lr->GetPhiRes(),probTr->GetZ()+rz*lr->GetZRes(), \r
-                              probTr->GetX(), probTr->GetAlpha() );    \r
-    //\r
-  }\r
-  //\r
-  return kTRUE;\r
-}\r
-\r
-//________________________________________________________________________________\r
-Bool_t KMCDetector::SolveSingleTrack(Double_t mass, Double_t pt, Double_t eta, TObjArray* sumArr,int nMC, int offset)\r
-{\r
-  // analityc and fullMC (nMC trials) evaluaion of tracks with given kinematics.\r
-  // the results are filled in KMCTrackSummary objects provided via summArr array\r
-  //\r
-  int progressP = 10;//0; // print progress in percents\r
-  //\r
-  progressP = int(nMC*0.01*progressP);\r
-\r
-  if (!SolveSingleTrackViaKalman(mass,pt,eta)) return kFALSE;\r
-  //\r
-  // Store non-updated track errors of inward propagated seed >>>>>>>>\r
-  int maxLr = fLastActiveITSLayer + offset;\r
-  if (maxLr >= fLastActiveLayerTracked-1) maxLr = fLastActiveLayerTracked;\r
-  KMCProbe probeTmp = fProbe; // original probe at vertex\r
-  KMCLayer* lr = 0;\r
-  for (Int_t j=1; j<=maxLr; j++) {\r
-    lr = GetLayer(j);\r
-    //    printf("Here0: %d\n",j);\r
-    if (!PropagateToLayer(&probeTmp,lr,1)) return 0;\r
-    if (j!=maxLr) if (!probeTmp.CorrectForMeanMaterial(lr, kFALSE)) return 0;\r
-    //    printf("Prelim. Err at lr:%8s | %7.3f %7.3f\n",lr->GetName(),TMath::Sqrt(probeTmp.GetSigmaY2()),TMath::Sqrt(probeTmp.GetSigmaZ2()));\r
-  }\r
-  for (Int_t j=maxLr; j>0; j--) {\r
-    lr = GetLayer(j);\r
-    //    printf("Here1: %d\n",j);\r
-    if (j!=maxLr) if (!PropagateToLayer(&probeTmp,lr,-1)) return 0;\r
-    lr->fSig2EstD = probeTmp.GetSigmaY2();\r
-    lr->fSig2EstZ = probeTmp.GetSigmaZ2();\r
-    //    probeTmp.Print("l");\r
-    printf("Natural Err at lr:%8s | %7.3f %7.3f\n",lr->GetName(),TMath::Sqrt(lr->fSig2EstD),TMath::Sqrt(lr->fSig2EstZ));\r
-    if (!probeTmp.CorrectForMeanMaterial(lr, kTRUE)) return 0;\r
-  }\r
-  // Store non-updated track errors of inward propagated seed <<<<<<<<\r
-  //\r
-  int nsm = sumArr ? sumArr->GetEntriesFast() : 0;\r
-  KMCLayer* vtx = GetLayer(0);\r
-  //\r
-  for (int i=0;i<nsm;i++) {\r
-    KMCTrackSummary* tsm = (KMCTrackSummary*)sumArr->At(i);\r
-    if (!tsm) continue;\r
-    tsm->SetRefProbe( GetProbeTrack() ); // attach reference track (generated)\r
-    tsm->SetAnProbe( vtx->GetAnProbe() ); // attach analitycal solution\r
-  }\r
-  //\r
-  TStopwatch sw;\r
-  sw.Start();\r
-  for (int it=0;it<nMC;it++) {\r
-    printf("ev: %d\n",it);\r
-    SolveSingleTrackViaKalmanMC(offset);\r
-    KMCProbe* trc = vtx->GetWinnerMCTrack();\r
-    vtx->GetMCTracks()->Print();\r
-    if (progressP==1 || (progressP>0 &&  (it%progressP)==0)) {\r
-      printf("%d%% done |",it*100/nMC); \r
-      sw.Stop(); sw.Print(); sw.Start(kFALSE);\r
-    }\r
-    for (int ism=nsm;ism--;) { // account the track in each of summaries\r
-      KMCTrackSummary* tsm = (KMCTrackSummary*)sumArr->At(ism);\r
-      if (!tsm) continue;\r
-      tsm->AddUpdCalls(GetUpdCalls());\r
-      tsm->AddTrack(trc); \r
-    }\r
-  }\r
-  //\r
-  sw.Stop();\r
-  printf("Total time: "); sw.Print();\r
-  return kTRUE;\r
-}\r
-\r
-//________________________________________________________________________________\r
-Int_t KMCDetector::GetLayerID(int actID) const\r
-{\r
-  // find physical layer id from active id\r
-  if (actID<0 || actID>fNActiveLayers) return -1;\r
-  int start = actID<fNActiveITSLayers ? fLastActiveITSLayer : fLastActiveLayer;\r
-  for (int i=start+1;i--;) {\r
-    if (GetLayer(i)->GetActiveID()==actID) return i;   \r
-  }\r
-  return -1;\r
-}\r
-\r
-//________________________________________________________________________________\r
-KMCProbe* KMCDetector::KalmanSmooth(int actLr, int actMin,int actMax) const\r
-{\r
-  // estimate kalman smoothed track params at given active lr \r
-  // from fit at layers actMin:actMax (excluding actLr)\r
-  // SolveSingleTrackViaKalman must have been called before\r
-  //\r
-  if (actMin>actMax) swap(actMin,actMax);\r
-  if (actMax>=fNActiveLayers) actMax = fNActiveLayers-1;\r
-  int nlrfit = actMax-actMin;\r
-  if (actLr>=actMin && actLr<=actMax) nlrfit-=1;\r
-  if (nlrfit<2) {AliInfo("Need a least 2 active layers in the fit"); return 0;}\r
-  static KMCProbe iwd,owd;\r
-  //\r
-  // find phisical layer id's\r
-  int pLr  = GetLayerID(actLr);\r
-  int pMin = GetLayerID(actMin);\r
-  int pMax = GetLayerID(actMax);\r
-  //\r
-  //  printf(">>> %d %d %d\n",pLr, pMin,pMax);\r
-  Bool_t useIwd=kFALSE, useOwd=kFALSE;\r
-  if (pLr<pMax) { // need inward piece\r
-    iwd = GetLayer(pMax)->fTrCorr;\r
-    iwd.ResetCovMat();\r
-    iwd.GetHitsPatt() = 0;\r
-    for (int i=pMax;i>=pLr;i--) {\r
-      KMCLayer* lr = GetLayer(i);\r
-      //      printf("IWD %d\n",i);\r
-      if (!lr->IsDead() && i!=pLr && i>=pMin) if (!UpdateTrack(&iwd,lr,&lr->fClCorr))  return 0;\r
-      if (i!=pLr) {\r
-       if (!iwd.CorrectForMeanMaterial(lr,kTRUE)) return 0; // correct for materials of this layer\r
-       if (!PropagateToLayer(&iwd,GetLayer(i-1),-1)) return 0;      // propagate to next layer\r
-      }\r
-      //  printf("IWD%d:  ",i); iwd.Print("l");\r
-    }\r
-    useIwd = kTRUE;\r
-  }\r
-  if (pLr>pMin) { // need outward piece\r
-    owd = GetLayer(pMin)->fTrCorr;\r
-    owd.ResetCovMat();\r
-    owd.GetHitsPatt() = 0;\r
-    for (int i=pMin;i<=pLr;i++) {\r
-      KMCLayer* lr = GetLayer(i);\r
-      //      printf("OWD %d\n",i);\r
-      if (!lr->IsDead() && i!=pLr && i<=pMax) if (!UpdateTrack(&owd,lr,&lr->fClCorr))  return 0;\r
-      if (i!=pLr) {\r
-       if (!owd.CorrectForMeanMaterial(lr,0)) return 0; // correct for materials of this layer\r
-       if (!PropagateToLayer(&owd,GetLayer(i+1), 1)) return 0;      // propagate to next layer\r
-      }\r
-      //      printf("OWD%d:  ",i); owd.Print("l");\r
-    }\r
-    useOwd = kTRUE;\r
-  }\r
-  //\r
-  // was this extrapolation outside the fit range?\r
-  if (!useIwd) return (KMCProbe*)&owd; \r
-  if (!useOwd) return (KMCProbe*)&iwd;\r
-  //\r
-  // weight both tracks\r
-  if (!iwd.Propagate(owd.GetAlpha(),owd.GetX(),fBFieldG)) return 0;\r
-  double meas[2] = {owd.GetY(),owd.GetZ()};\r
-  double measErr2[3] = {owd.GetSigmaY2(), owd.GetSigmaZY(), owd.GetSigmaZ2()};\r
-  //  printf("Weighting\n");\r
-  //  owd.Print("l");\r
-  //  iwd.Print("l");\r
-  if (!iwd.Update(meas,measErr2)) return 0;\r
-  iwd.GetHitsPatt() |= owd.GetHitsPatt();\r
-\r
-  //  printf("->\n");\r
-  //  iwd.Print("l");\r
-\r
-  return (KMCProbe*)&iwd;\r
-  //\r
-}\r
-\r
-//________________________________________________________________________________\r
-KMCProbe* KMCDetector::KalmanSmoothFull(int actLr, int actMin,int actMax) const\r
-{\r
-  // estimate kalman smoothed track params at given active lr \r
-  // from fit at layers actMin:actMax (excluding actLr)\r
-  // SolveSingleTrackViaKalman must have been called before\r
-  //\r
-  static TClonesArray prediction("KMCProbe",10);\r
-  static TClonesArray update("KMCProbe",10);\r
-  static KMCProbe res;\r
-  //\r
-  if (actMin>actMax) swap(actMin,actMax);\r
-  int nlrfit = actMax-actMin;\r
-  if (actLr>=actMin && actLr<=actMax) nlrfit-=1;\r
-  if (nlrfit<2) {AliInfo("Need a least 2 active layers in the fit"); return 0;}\r
-  //\r
-  // find phisical layer id's\r
-  int pLr  = GetLayerID(actLr);\r
-  int pMin = GetLayerID(actMin);\r
-  int pMax = GetLayerID(actMax);\r
-  //\r
-  int dir=0,dirInt=0;\r
-  if      (pLr<=pMin) dir=-1; // inward extrapolation\r
-  else if (pLr>=pMax) dir= 1; // outward extrapolation\r
-  else if (actMax-actLr >= actLr-actMin) dirInt = -1; // inward  interpolation (the test point is closer to inner layer)\r
-  else    dirInt = 1;                                 // outward interpolation (the test point is closer to outer layer)\r
-  //\r
-  if (dir!=0) { // no sens to do smoothing: simple Kalman filtering extrapolation\r
-    int start = dir<0 ? pMax : pMin;\r
-    res = GetLayer(start)->fTrCorr;\r
-    res.ResetCovMat();\r
-    KMCLayer* lr = 0;\r
-    for (int i=(dir<0?pMax:pMin); i!=pLr; i+=dir) { // track till nearest layer to pLr\r
-      lr = GetLayer(i);\r
-      if (!lr->IsDead() && !(i<pMin ||i>pMax)) if (!UpdateTrack(&res,lr,&lr->fClCorr))  return 0; // update only with layers in fit range\r
-      if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this layer\r
-      if (!PropagateToLayer(&res,GetLayer(i+dir),dir))            return 0; // propagate to next layer     \r
-    }\r
-    if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this nearest layer\r
-    if (!PropagateToLayer(&res,GetLayer(pLr), dir)) return 0; // propagate to test layer\r
-    return (KMCProbe*)&res;\r
-  }\r
-  //\r
-  // too bad, need to do real filtering\r
-  //\r
-  int start = dirInt<0 ? pMax : pMin;\r
-  int stop  = dirInt<0 ? pMin-1 : pMax+1;\r
-  res = GetLayer(start)->fTrCorr;\r
-  res.ResetCovMat();\r
-  KMCLayer* lr = 0;\r
-  int count = 0;\r
-  for (int i=start; i!=stop; i+=dirInt) { // track in full range, storing updates and predictions\r
-    new(prediction[count]) KMCProbe(res);\r
-    lr = GetLayer(i);\r
-    if (!lr->IsDead() && i!=pLr) if (!UpdateTrack(&res,lr,&lr->fClCorr))  return 0; // update only with layers in fit range\r
-    new(update[count]) KMCProbe(res);\r
-    if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this layer\r
-    if (!PropagateToLayer(&res,GetLayer(i+dir),dir))            return 0; // propagate to next layer     \r
-    count++;\r
-  }\r
-  return (KMCProbe*)&res;\r
-  //\r
-}\r
-\r
-//________________________________________________________________________________\r
-Bool_t KMCDetector::SolveSingleTrackViaKalman(Double_t mass, Double_t pt, Double_t eta)\r
-{\r
-  // analytical estimate of tracking resolutions\r
-  //  fProbe.SetUseLogTermMS(kTRUE);\r
-  //\r
-  if (fMinITSHits>fNActiveITSLayers) {fMinITSHits = fNActiveITSLayers; printf("Redefined request of min N ITS hits to %d\n",fMinITSHits);}\r
-  if (TMath::Abs(eta)<1e-3) fDensFactorEta = 1.;\r
-  else {\r
-    fDensFactorEta = TMath::Tan( 2.*TMath::ATan(TMath::Exp(-TMath::Abs(eta))) );\r
-    fDensFactorEta = 1./TMath::Sqrt( 1. + 1./fDensFactorEta/fDensFactorEta);\r
-  }\r
-  double lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-eta)); \r
-  KMCProbe* probe = PrepareKalmanTrack(pt,lambda,mass,-1);\r
-  if (!probe) return kFALSE;\r
-  //\r
-  KMCLayer *lr = 0;\r
-  //\r
-  //\r
-  // Start the track fitting --------------------------------------------------------\r
-  //\r
-  // Back-propagate the covariance matrix along the track. \r
-  // Kalman loop over the layers\r
-  //\r
-  KMCProbe* currTr = 0;\r
-  lr = (KMCLayer*)fLayers.At(fLastActiveLayerTracked);\r
-  lr->fTrCorr = *probe;\r
-  delete probe; // rethink...\r
-  //\r
-  for (Int_t j=fLastActiveLayerTracked; j--; ) {  // Layer loop\r
-    //\r
-    KMCLayer *lrP = lr;\r
-    lr = (KMCLayer*)fLayers.At(j);\r
-    //\r
-    lr->fTrCorr = lrP->fTrCorr;\r
-    currTr = &lr->fTrCorr;\r
-    currTr->ResetHit(lrP->GetActiveID());\r
-    //\r
-    // if there was a measurement on prev layer, update the track\r
-    if (!lrP->IsDead()) { // include measurement\r
-      KMCCluster cl(currTr->GetY(),currTr->GetZ(), currTr->GetX(), currTr->GetAlpha());\r
-      if (!UpdateTrack(currTr,lrP,&cl))  return kFALSE;\r
-    }\r
-    if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) return kFALSE; // correct for materials of this layer\r
-    if (!PropagateToLayer(currTr,lr,-1)) return kFALSE;      // propagate to current layer\r
-    //\r
-  } // end loop over layers\r
-  //\r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________________________________\r
-Bool_t KMCDetector::SolveSingleTrackViaKalmanMC(int offset)\r
-{\r
-  // MC estimate of tracking resolutions/effiencies. Requires that the SolveSingleTrackViaKalman\r
-  // was called before, since it uses data filled by this method\r
-  //\r
-  // The MC tracking will be done starting from fLastActiveITSLayer + offset (before analytical estimate will be used)\r
-  //\r
-  // At this point, the fProbe contains the track params generated at vertex.\r
-  // Clone it and propagate to target layer to generate hit positions affected by MS\r
-  //\r
-  fUpdCalls = 0.;\r
-  KMCProbe *currTrP=0,*currTr=0;\r
-  int maxLr = fLastActiveITSLayer + offset;\r
-  if (maxLr >= fLastActiveLayerTracked-1) maxLr = fLastActiveLayerTracked;\r
-  ResetMCTracks(maxLr);\r
-  KMCLayer* lr = (KMCLayer*)fLayers.At(maxLr);\r
-  currTr = lr->AddMCTrack(&fProbe); // start with original track at vertex\r
-  //\r
-  if (!TransportKalmanTrackWithMS(currTr, maxLr)) return kFALSE; // transport it to outermost layer where full MC is done\r
-  //\r
-  if (fLastActiveITSLayer<fLastActiveLayerTracked) { // prolongation from TPC\r
-    // start from correct track propagated from above till maxLr\r
-    double *covMS = (double*)currTr->GetCovariance();\r
-    const double *covIdeal =lr->fTrCorr.GetCovariance();\r
-    for (int i=15;i--;) covMS[i] = covIdeal[i];\r
-  }\r
-  else { // ITS SA: randomize the starting point\r
-    //    double *pars = (double*)currTr->GetParameter();\r
-    //    pars[0] += gRandom->Gaus(0,TMath::Sqrt(currTr->GetSigmaY2()));\r
-    //    pars[1] += gRandom->Gaus(0,TMath::Sqrt(currTr->GetSigmaZ2()));\r
-    //\r
-    currTr->ResetCovMat();\r
-    /*\r
-    double *trCov  = (double*)currTr->GetCovariance();\r
-    double *trPars = (double*)currTr->GetParameter();\r
-    const double kLargeErr2PtI = 0.3*0.3;\r
-    trCov[14] = TMath::Max(trCov[14],kLargeErr2PtI*trPars[4]*trPars[4]);\r
-    */\r
-  }\r
-  //\r
-  for (Int_t j=maxLr; j--; ) {  // Layer loop\r
-    //\r
-    KMCLayer *lrP = lr;\r
-    lr = (KMCLayer*)fLayers.At(j);\r
-    int ntPrev = lrP->GetNMCTracks();\r
-    //\r
-    if (lrP->IsDead()) { // for passive layer just propagate the copy of all tracks of prev layer >>>\r
-      for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer\r
-       currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;\r
-       currTr = lr->AddMCTrack( currTrP );\r
-       if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill(); continue;} // correct for materials of prev. layer\r
-       if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill(); continue;} // propagate to current layer\r
-      }\r
-      continue;\r
-    } // treatment of dead layer <<<\r
-    //\r
-    if (lrP->IsTPC()) { // we don't consider bg hits in TPC, just update with MC cluster\r
-      for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer\r
-       currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;\r
-       currTr = lr->AddMCTrack( currTrP );\r
-       if (!UpdateTrack(currTr, lrP, lrP->GetMCCluster(), kTRUE)) {currTr->Kill(); continue;} // update with correct MC cl.\r
-       if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill(); continue;} // correct for materials of prev. layer\r
-       if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill(); continue;} // propagate to current layer\r
-      }\r
-      continue;\r
-    } // treatment of ideal (TPC?) layer <<<\r
-    //\r
-    // active layer under eff. study (ITS?): propagate copy of every track to MC cluster frame (to have them all in the same frame)\r
-    // and calculate the limits of bg generation\r
-    KMCCluster* clMC = lrP->GetMCCluster();\r
-    if (lrP->GetLayerEff()<gRandom->Rndm()) clMC->Kill(); // simulate inefficiency\r
-    ResetSearchLimits();\r
-    int nseeds = 0;\r
-    for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer\r
-      currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;\r
-      currTr = lr->AddMCTrack( currTrP );\r
-      if (!currTr->PropagateToCluster(clMC,fBFieldG)) {currTr->Kill(); continue;} // go to MC cluster\r
-      if ( !(currTr->GetNITSHits()>0 && currTr->GetNITSHits()==currTr->GetNFakeITSHits()) ) UpdateSearchLimits(currTr, lrP); // RS\r
-      nseeds++;\r
-    }\r
-    //\r
-    //    printf("%3d seeds\n",nseeds);\r
-    if (fUseBackground && lrP->IsITS()) GenBgClusters(lrP); //  generate background hits\r
-    //\r
-    ntPrev = lr->GetNMCTracks();\r
-    for (int itr=ntPrev;itr--;) { // loop over all tracks PROPAGATED from previous layer to clusters frame on previous layer\r
-      currTrP = lr->GetMCTrack(itr); // this is a seed from prev layer. The new clusters are attached to its copies, the seed itself\r
-                                     // will be propagated w/o cluster update if it does not violate requested "reconstructed" track settings\r
-      if (currTrP->IsKilled()) continue;\r
-      //printf("Check    %d %p %d\n",itr,currTrP,currTrP->GetUniqueID()); currTrP->Print();\r
-      CheckTrackProlongations(currTrP, lr, lrP);\r
-      if (NeedToKill(currTrP)) currTrP->Kill(); // kill track which was not updated at lrP\r
-      //currTrP->Kill(); // kill track which was not updated at lrP\r
-    }\r
-    //  \r
-    lr->GetMCTracks()->Sort();\r
-    int ntTot = lr->GetNMCTracks(); // propagate max amount of allowed tracks to current layer\r
-    if (ntTot>fMaxSeedToPropagate && fMaxSeedToPropagate>0) {\r
-      for (int itr=ntTot;itr>=fMaxSeedToPropagate;itr--)  lr->GetMCTracks()->RemoveAt(itr);\r
-      ntTot = fMaxSeedToPropagate;\r
-    }\r
-    //\r
-    for (int itr=ntTot;itr--;) {\r
-      currTr = lr->GetMCTrack(itr);\r
-      if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill();continue;} // correct for materials of prev. layer\r
-      if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill();continue;} // propagate to current layer\r
-    }\r
-    AliDebug(1,Form("Got %d tracks on layer %s",ntTot,lr->GetName()));\r
-    //    lr->GetMCTracks()->Print();\r
-    //\r
-  } // end loop over layers    \r
-  //\r
-  // do we use vertex constraint?\r
-  KMCLayer *vtx = GetLayer(0);\r
-  if (!vtx->IsDead() && vtx->IsITS()) {\r
-    int ntr = vtx->GetNMCTracks();\r
-    for (int itr=0;itr<ntr;itr++) {\r
-      currTr = vtx->GetMCTrack(itr);\r
-      if (currTr->IsKilled()) continue;\r
-      KMCCluster* clv = vtx->GetMCCluster();\r
-      double meas[2] = {clv->GetY(),clv->GetZ()};\r
-      double measErr2[3] = {vtx->fPhiRes*vtx->fPhiRes,0,vtx->fZRes*vtx->fZRes};\r
-      double chi2v = currTr->GetPredictedChi2(meas,measErr2);\r
-      currTr->AddHit(vtx->GetActiveID(), chi2v, -1);\r
-      currTr->SetInnerLrChecked(vtx->GetActiveID());\r
-      if (NeedToKill(currTr)) currTr->Kill();\r
-      // if (vtx->IsITS()) {if (!UpdateTrack(currTr, vtx, vtx->GetMCCluster(), kFALSE)) {currTr->Kill();continue;}}\r
-    }\r
-  }\r
-  EliminateUnrelated();\r
-  \r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________________________________________________\r
-Bool_t KMCDetector::PropagateToLayer(KMCProbe* trc, KMCLayer* lr, int dir) const\r
-{\r
-  // bring the track to layer and rotat to frame normal to its surface\r
-  if (!trc->PropagateToR(lr->fR,fBFieldG, dir)) return kFALSE;\r
-  //\r
-  // rotate to frame with X axis normal to the surface (defined by ideal track)\r
-  if (!lr->IsVertex()) {\r
-    double pos[3];\r
-    trc->GetXYZ(pos);  // lab position\r
-    double phi = TMath::ATan2(pos[1],pos[0]);\r
-    if ( TMath::Abs(TMath::Abs(phi)-TMath::Pi()/2)<1e-3) phi = 0;\r
-    if (!trc->Rotate(phi)) {\r
-      AliDebug(2,Form("Failed to rotate to the frame (phi:%+.3f) of layer at %.2f at XYZ: %+.3f %+.3f %+.3f",\r
-                     phi,lr->fR,pos[0],pos[1],pos[2]));\r
-      if (AliLog::GetGlobalDebugLevel()>1) trc->Print("l");\r
-      return kFALSE;\r
-    }\r
-  }\r
-  //\r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________________________________________________\r
-Bool_t KMCDetector::UpdateTrack(KMCProbe* trc, KMCLayer* lr, KMCCluster* cl, Bool_t goToCluster) const\r
-{\r
-  // update track with measured cluster\r
-  // propagate to cluster\r
-  double meas[2] = {cl->GetY(),cl->GetZ()}; // ideal cluster coordinate\r
-  double measErr2[3] = {lr->fPhiRes*lr->fPhiRes,0,lr->fZRes*lr->fZRes};\r
-  //\r
-  if (goToCluster) if (!trc->PropagateToCluster(cl,fBFieldG)) return kFALSE; // track was not propagated to cluster frame\r
-  //\r
-  double chi2 = trc->GetPredictedChi2(meas,measErr2);\r
-  //  if (chi2>fMaxChi2Cl) return kTRUE; // chi2 is too large\r
-  //  \r
-  if (!trc->Update(meas,measErr2)) {\r
-    AliDebug(2,Form("layer %s: Failed to update the track by measurement {%.3f,%3f} err {%.3e %.3e %.3e}",\r
-                   lr->GetName(),meas[0],meas[1], measErr2[0],measErr2[1],measErr2[2]));\r
-    if (AliLog::GetGlobalDebugLevel()>1) trc->Print("l");\r
-    return kFALSE;\r
-  }\r
-  trc->AddHit(lr->GetActiveID(), chi2);\r
-  //\r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________________________________________________\r
-Int_t KMCDetector::GenBgClusters(KMCLayer* lr)\r
-{\r
-  // Generate fake clusters in precalculated RPhi,Z range\r
-  if (fNBgLimits<1) return 0; // limits were not set - no track was prolongated\r
-  //\r
-  // Fix search limits to avoid seeds which will anyway point very far from the vertex\r
-  double tolY = TMath::Sqrt(lr->fSig2EstD)*fMaxChi2ClSQ;\r
-  double tolZ = TMath::Sqrt(lr->fSig2EstZ)*fMaxChi2ClSQ;\r
-  \r
-  //  printf("Before: Y: %+6.3f : %+6.3f tolY: %6.3f || Z: %+6.3f : %+6.3f tolZ: %6.3f\n",fBgYMin,fBgYMax,tolY, fBgZMin,fBgZMax,tolZ);\r
-  if (fBgYMin < lr->fClCorr.fY-tolY) fBgYMin = lr->fClCorr.fY-tolY;\r
-  if (fBgYMax > lr->fClCorr.fY+tolY) fBgYMax = lr->fClCorr.fY+tolY;\r
-  if (fBgZMin < lr->fClCorr.fZ-tolZ) fBgZMin = lr->fClCorr.fZ-tolZ;\r
-  if (fBgZMax > lr->fClCorr.fZ+tolZ) fBgZMax = lr->fClCorr.fZ+tolZ;\r
-  //printf("After: Y: %+6.3f : %+6.3f tolY: %6.3f || Z: %+6.3f : %+6.3f tolZ: %6.3f\n",fBgYMin,fBgYMax,tolY, fBgZMin,fBgZMax,tolZ);\r
-  //\r
-  double dy = fBgYMax - fBgYMin;\r
-  double dz = fBgZMax - fBgZMin;\r
-  double surf = dy*dz;               // surface of generation\r
-  if (surf<0) return 0;\r
-  double poissProb = surf*HitDensity(lr->fR)*lr->GetLayerEff();\r
-  AliDebug(2,Form("Bg for Lr %s (r=%.2f) : Density %.2f on surface %.2e [%+.4f : %+.4f][%+.4f %+.4f]",\r
-                 lr->GetName(),lr->fR,HitDensity(lr->fR),surf,fBgYMin,fBgYMax,fBgZMin,fBgZMax));\r
-  int nFakesGen = gRandom->Poisson( poissProb ); // preliminary number of extra clusters to test\r
-  KMCCluster *refCl = lr->GetMCCluster();\r
-  double sig2y = lr->GetPhiRes()*lr->GetPhiRes();\r
-  double sig2z = lr->GetZRes()*lr->GetZRes();\r
-  for (int ic=nFakesGen;ic--;) {\r
-    double y = fBgYMin+dy*gRandom->Rndm();\r
-    double z = fBgZMin+dz*gRandom->Rndm();\r
-    double dfy = y-refCl->GetY();\r
-    double dfz = z-refCl->GetZ();\r
-    double dist = (dfy*dfy)/sig2y + (dfz*dfz)/sig2z;\r
-    if (dist<4) continue; // avoid overlap with MC cluster\r
-    lr->AddBgCluster(y, z, refCl->GetX(), refCl->GetPhi());\r
-  }\r
-  AliDebug(2,Form("Added %6d noise clusters on lr %s (poisson Prob=%8.2f for surface %.2e) DY:%7.4f DZ: %7.4f",\r
-                  lr->GetNBgClusters(),lr->GetName(),poissProb,surf,dy,dz));\r
-  return nFakesGen;\r
-  //\r
-}\r
-\r
-//____________________________________________________________________________\r
-void KMCDetector::UpdateSearchLimits(KMCProbe* probe, KMCLayer* lr)\r
-{\r
-  // define the search window for track on layer (where the bg hist will be generated)\r
-  static double *currYMin = fBgYMinTr.GetArray();\r
-  static double *currYMax = fBgYMaxTr.GetArray();\r
-  static double *currZMin = fBgZMinTr.GetArray();\r
-  static double *currZMax = fBgZMaxTr.GetArray();\r
-  //\r
-  double sizeY = probe->GetSigmaY2(), sizeZ = probe->GetSigmaZ2();\r
-  //  /*\r
-  if (probe->GetNITSHits()<3) sizeY = 10*lr->fSig2EstD;\r
-  if (probe->GetNITSHits()<2) sizeZ = 10*lr->fSig2EstZ;\r
-  sizeY = fMaxChi2ClSQ*TMath::Sqrt(sizeY+lr->fPhiRes*lr->fPhiRes); // max deviation in rphi to accept\r
-  sizeZ = fMaxChi2ClSQ*TMath::Sqrt(sizeZ+lr->fZRes*lr->fZRes); // max deviation in dz to accept\r
-  //  */\r
-  //\r
-  /*\r
-  if (probe->GetNITSHits()<3) sizeY = 1./(1./lr->fSig2EstD + 1./sizeY);\r
-  if (probe->GetNITSHits()<2) sizeZ = 1./(1./lr->fSig2EstZ + 1./sizeZ);\r
-  sizeY = fMaxChi2ClSQ*TMath::Sqrt(sizeY); // max deviation in rphi to accept\r
-  sizeZ = fMaxChi2ClSQ*TMath::Sqrt(sizeZ); // max deviation in dz to accept\r
-  */\r
-  //\r
-  //  if (sizeY>2) sizeY=2;\r
-  //  if (sizeZ>2) sizeZ=2;\r
-  //  printf("Sizes at %s: %.5f %.5f\n",lr->GetName(), sizeY,sizeZ);\r
-  //\r
-  if (fNBgLimits>=fBgYMinTr.GetSize()) { // expand arrays, update pointers\r
-    fBgYMinTr.Set(2*(fNBgLimits+1));\r
-    fBgYMaxTr.Set(2*(fNBgLimits+1));\r
-    fBgZMinTr.Set(2*(fNBgLimits+1));\r
-    fBgZMaxTr.Set(2*(fNBgLimits+1));\r
-    currYMin = fBgYMinTr.GetArray();\r
-    currYMax = fBgYMaxTr.GetArray();\r
-    currZMin = fBgZMinTr.GetArray();\r
-    currZMax = fBgZMaxTr.GetArray();\r
-  }\r
-  if (fBgYMin > (currYMin[fNBgLimits]=probe->GetY()-sizeY) ) fBgYMin = currYMin[fNBgLimits];\r
-  if (fBgYMax < (currYMax[fNBgLimits]=probe->GetY()+sizeY) ) fBgYMax = currYMax[fNBgLimits];\r
-  if (fBgZMin > (currZMin[fNBgLimits]=probe->GetZ()-sizeZ) ) fBgZMin = currZMin[fNBgLimits];\r
-  if (fBgZMax < (currZMax[fNBgLimits]=probe->GetZ()+sizeZ) ) fBgZMax = currZMax[fNBgLimits];\r
-  if (AliLog::GetGlobalDebugLevel()>=2) {\r
-    probe->Print("l");\r
-    AliInfo(Form("Seed%3d Lr %s limits for y:%+8.4f z:%+8.4f [%+.4f : %+.4f][%+.4f %+.4f]",fNBgLimits,lr->GetName(),probe->GetY(),probe->GetZ(),currYMin[fNBgLimits],currYMax[fNBgLimits],currZMin[fNBgLimits],currZMax[fNBgLimits]));\r
-    AliInfo(Form("Global Limits Lr %s                            [%+.4f : %+.4f][%+.4f %+.4f]",lr->GetName(),fBgYMin,fBgYMax,fBgZMin,fBgZMax));\r
-    AliInfo(Form("MC Cluster: %+.4f : %+.4f",lr->fClMC.fY, lr->fClMC.fZ));\r
-  }\r
-  probe->SetUniqueID(fNBgLimits++);\r
-  //\r
-  if (lr->IsITS() && probe->GetNFakeITSHits()==0) {\r
-    if (fHMCLrResidRPhi) fHMCLrResidRPhi->Fill(probe->GetY() - lr->GetMCCluster()->GetY(), lr->GetActiveID());\r
-    if (fHMCLrResidZ)    fHMCLrResidZ->Fill(probe->GetZ() - lr->GetMCCluster()->GetZ(),lr->GetActiveID());\r
-  }\r
-  //\r
-}\r
-\r
-//____________________________________________________________________________\r
-void KMCDetector::CheckTrackProlongations(KMCProbe *probe, KMCLayer* lr, KMCLayer* lrP)\r
-{\r
-  // explore prolongation of probe from lrP to lr with all possible clusters of lrP\r
-  // the probe is already brought to clusters frame\r
-  int nCl = lrP->GetNBgClusters();\r
-  double measErr2[3] = {lrP->fPhiRes*lrP->fPhiRes,0,lrP->fZRes*lrP->fZRes};\r
-  double meas[2] = {0,0};\r
-  UInt_t tmpID = probe->GetUniqueID();\r
-  double yMin = fBgYMinTr[tmpID];\r
-  double yMax = fBgYMaxTr[tmpID];\r
-  double zMin = fBgZMinTr[tmpID];\r
-  double zMax = fBgZMaxTr[tmpID];\r
-  //\r
-  probe->SetInnerLrChecked(lrP->GetActiveID());\r
-  for (int icl=-1;icl<nCl;icl++) {\r
-    KMCCluster* cl = icl<0 ? lrP->GetMCCluster() : lrP->GetBgCluster(icl);  // -1 is for true MC cluster\r
-    if (cl->IsKilled()) {\r
-      if (AliLog::GetGlobalDebugLevel()>1) {printf("Skip cluster %d ",icl); cl->Print();}\r
-      continue;\r
-    }\r
-    double y = cl->GetY();\r
-    double z = cl->GetZ();\r
-    AliDebug(2,Form("Check seed%d against cl#%d out of %d at layer %s | y:%+8.4f z:%+8.4f [%+.4f:%+.4f]  [%+.4f:%+.4f]",tmpID,icl,nCl,lrP->GetName(),y,z,yMin,yMax,zMin,zMax));\r
-    if (AliLog::GetGlobalDebugLevel()>0) {\r
-      if (icl==-1 && probe->GetNFakeITSHits()==0) {\r
-       meas[0] = y; meas[1] = z;\r
-       double chi2a = probe->GetPredictedChi2(meas,measErr2);\r
-       if (chi2a>fMaxChi2Cl || (y<yMin || y>yMax) || (z<zMin || z>zMax)) {\r
-         probe->Print();\r
-         printf("Loosing good point (y:%+8.4f z:%+8.4f) on lr %s: chi2: %.2f  | dy:%+8.4f dz:%+8.4f [%+.4f:%+.4f]  [%+.4f:%+.4f] |x: %.2f %.2f | phi: %.2f %.2f\n",\r
-                y,z,lrP->GetName(),chi2a,y-probe->GetY(),z-probe->GetZ(),yMin,yMax,zMin,zMax, probe->GetX(), cl->GetX(), probe->GetAlpha(), cl->GetPhi());\r
-       }\r
-      }\r
-    }\r
-    if (y<yMin || y>yMax) continue; // preliminary check on Y\r
-    if (z<zMin || z>zMax) continue; // preliminary check on Z\r
-    meas[0] = y; meas[1] = z;\r
-    double chi2 = probe->GetPredictedChi2(meas,measErr2);\r
-    if (fHMCLrChi2 && probe->GetNFakeITSHits()==0 && icl==-1) fHMCLrChi2->Fill(chi2,lrP->GetActiveID());\r
-    AliDebug(2,Form("Seed-to-cluster chi2 = Chi2=%.2f",chi2));\r
-    if (chi2>fMaxChi2Cl) continue;\r
-    // \r
-    // update track copy\r
-    KMCProbe* newTr = lr->AddMCTrack( probe );\r
-    fUpdCalls++;\r
-    if (!newTr->Update(meas,measErr2)) {\r
-      AliDebug(2,Form("Layer %s: Failed to update the track by measurement {%.3f,%3f} err {%.3e %.3e %.3e}",\r
-                     lrP->GetName(),meas[0],meas[1], measErr2[0],measErr2[1],measErr2[2]));\r
-      if (AliLog::GetGlobalDebugLevel()>1) newTr->Print("l");\r
-      newTr->Kill();\r
-      continue;\r
-    }\r
-    newTr->AddHit(lrP->GetActiveID(), chi2, icl);\r
-    if (AliLog::GetGlobalDebugLevel()>1) {\r
-      AliInfo("Cloned updated track is:");\r
-      newTr->Print();\r
-    }\r
-    if (NeedToKill(newTr)) newTr->Kill();\r
-  }\r
-  //\r
-}\r
-\r
-//____________________________________________________________________________\r
-void KMCDetector::ResetMCTracks(Int_t maxLr)\r
-{\r
-  int nl = GetNLayers();\r
-  if (maxLr<0 || maxLr>=nl) maxLr = nl-1;\r
-  for (int i=maxLr+1;i--;) GetLayer(i)->ResetMCTracks();\r
-}\r
-\r
-//____________________________________________________________________________\r
-Bool_t KMCDetector::NeedToKill(KMCProbe* probe) const\r
-{\r
-  // check if the seed at given layer (last one where update was tried) \r
-  // still has chances to be reconstructed\r
-  const Bool_t kModeKillMiss = kFALSE;\r
-  //\r
-  Bool_t kill = kFALSE;\r
-  while (1) {\r
-    int il = probe->GetInnerLayerChecked();\r
-    int nITS = probe->GetNITSHits();\r
-    int nITSMax = nITS + il; // maximum it can have\r
-    if (nITSMax<fMinITSHits) {\r
-      kill = kTRUE; \r
-      break;\r
-    }    // has no chance to collect enough ITS hits\r
-    //\r
-    int ngr = fPattITS.GetSize();\r
-    if (ngr>0) { // check pattern\r
-      UInt_t patt = probe->GetHitsPatt();\r
-      // complete the layers not checked yet\r
-      for (int i=il;i--;) patt |= (0x1<<i);\r
-      for (int ig=ngr;ig--;) \r
-       if (!(((UInt_t)fPattITS[ig]) & patt)) {\r
-         kill = kTRUE; \r
-         break;\r
-       }\r
-      //\r
-    }\r
-    //\r
-    if (nITS>2) {  // check if smallest possible norm chi2/ndf is acceptable\r
-      double chi2min = probe->GetChi2();\r
-      if (kModeKillMiss) {\r
-       int nMiss = fNActiveITSLayers - probe->GetInnerLayerChecked() - nITS; // layers already missed\r
-       chi2min = nMiss*probe->GetMissingHitPenalty();\r
-      }\r
-      chi2min /= ((nITSMax<<1)-KMCProbe::kNDOF);\r
-      if (chi2min>fMaxNormChi2NDF) {\r
-       kill = kTRUE; \r
-       break;\r
-      }\r
-    }\r
-    //\r
-    // loose vertex constraint\r
-    double dst;\r
-    if (nITS>=2) {\r
-      probe->GetZAt(0,fBFieldG,dst);\r
-      //printf("Zd (F%d): %f\n",probe->GetNFakeITSHits(),dst);\r
-      if (TMath::Abs(dst)>10.) {\r
-       kill = kTRUE; \r
-       break;\r
-      }\r
-    }\r
-    if (nITS>=3) {\r
-      probe->GetYAt(0,fBFieldG,dst);\r
-      //printf("Dd (F%d): %f\n",probe->GetNFakeITSHits(),dst);\r
-      if (TMath::Abs(dst)>10.) {\r
-       kill = kTRUE; \r
-       break;\r
-      }\r
-    }\r
-    //\r
-    break;\r
-  }\r
-  if (kill && AliLog::GetGlobalDebugLevel()>1 && probe->GetNFakeITSHits()==0) {\r
-    printf("Killing good seed, last upd layer was %d\n",probe->GetInnerLayerChecked());\r
-    probe->Print("l");\r
-  }\r
-  return kill;\r
-}\r
-\r
-//_____________________________________________________________________\r
-void KMCDetector::EliminateUnrelated()\r
-{\r
-  // kill useless tracks\r
-  KMCLayer* lr = GetLayer(0);\r
-  int ntr = lr->GetNMCTracks();\r
-  int nval = 0;\r
-  for (int itr=0;itr<ntr;itr++) {\r
-    KMCProbe* probe = lr->GetMCTrack(itr);\r
-    if (probe->IsKilled()) continue;\r
-    if (probe->GetNITSHits()-probe->GetNFakeITSHits()<1) {probe->Kill(); continue;}\r
-    nval++;\r
-  }\r
-  lr->GetMCTracks()->Sort();\r
-  const int kDump = 0;\r
-  if (kDump>0) {\r
-    printf("Valid %d out of %d\n",nval, ntr);\r
-    ntr = ntr>kDump ? kDump:0;\r
-    for (int itr=0;itr<ntr;itr++) {\r
-      lr->GetMCTrack(itr)->Print();\r
-    }\r
-  }\r
-}\r
-\r
-//_____________________________________________________________________\r
-void KMCDetector::RequirePattern(UInt_t *patt, int groups)\r
-{\r
-  if (groups<1) {fPattITS.Set(0); return;}\r
-  fPattITS.Set(groups);\r
-  for (int i=0;i<groups;i++) fPattITS[i] = patt[i];\r
-}\r
-\r
-//_____________________________________________________________________\r
-void KMCDetector::CalcHardSearchLimits(double dzv)\r
-{\r
-  //\r
-  TArrayD zlims;\r
-  zlims.Set(fNActiveITSLayers);\r
-  for (int il0=0;il0<fNActiveITSLayers;il0++) {\r
-    KMCLayer* lr0 = GetActiveLayer(il0);\r
-    double angZTol = dzv/lr0->GetRadius();\r
-    for (int il1=0;il1<fNActiveITSLayers;il1++) {\r
-      if (il1==il0) continue;\r
-      KMCLayer* lr1 = GetActiveLayer(il1);\r
-      double ztol = angZTol*TMath::Abs(lr0->GetRadius() - lr1->GetRadius());\r
-      if (ztol>zlims[il1]) zlims[il1] = ztol;\r
-    }\r
-  }\r
-  //\r
-  for (int il=0;il<fNActiveITSLayers;il++) printf("ZTol%d: %8.4f\n",il,zlims[il]);\r
-}\r
-\r
-//_______________________________________________________\r
-double KMCDetector::PropagateBack(KMCProbe* trc) \r
-{\r
-  static KMCProbe bwd;\r
-  bwd = *trc;\r
-  bwd.ResetCovMat();\r
-  static double measErr2[3] = {0,0,0};\r
-  static double meas[2] = {0,0};\r
-  int icl = 0;\r
-  double chi2Tot = 0;\r
-  for (int il=1;il<=fLastActiveITSLayer;il++) {\r
-    KMCLayer* lr = GetLayer(il);\r
-    if (!PropagateToLayer(&bwd,lr,1)) return -1;\r
-    int aID = lr->GetActiveID();\r
-    if (aID>-1 && (icl=bwd.fClID[aID])>=-1) {\r
-      KMCCluster* clMC =  icl<0 ? lr->GetMCCluster() : lr->GetBgCluster(icl);\r
-      if (!bwd.PropagateToCluster(clMC,fBFieldG)) return -1;\r
-      meas[0] = clMC->GetY(); meas[1] = clMC->GetZ();\r
-      measErr2[0] = lr->fPhiRes*lr->fPhiRes;\r
-      measErr2[2] = lr->fZRes*lr->fZRes;\r
-      double chi2a = bwd.GetPredictedChi2(meas,measErr2);\r
-      chi2Tot += chi2a;\r
-      printf("Chis %d (cl%+3d): t2c: %6.3f tot: %6.3f\n",aID,icl,chi2a, chi2Tot);\r
-      bwd.Update(meas,measErr2);\r
-      bwd.AddHit(aID, chi2a, icl);     \r
-    }\r
-    if (!bwd.CorrectForMeanMaterial(lr,kFALSE)) return -1;\r
-  }\r
-  return chi2Tot;\r
-}\r
-\r
-\r
-//////////////////////////////////////////////////////////////////////////////////////////////\r
-//--------------------------------------------------------------------------------------------\r
-ClassImp(KMCTrackSummary)\r
-\r
-Int_t KMCTrackSummary::fgSumCounter = 0;\r
-\r
-//____________________________________________________________________________\r
-KMCTrackSummary::KMCTrackSummary(const char* name,const char* title, int nlr) :\r
-  TNamed(name,name), fNITSLayers(nlr),\r
-  fPattITS(0),fPattITSFakeExcl(0),fPattITSCorr(0),\r
-  fHMCChi2(0),fHMCSigDCARPhi(0),fHMCSigDCAZ(0),fHMCSigPt(0),fHMCNCl(0),fHMCFakePatt(0),\r
-  fCountAcc(0),fCountTot(0),fUpdCalls(0),\r
-  fRefProbe(),fAnProbe()\r
-{\r
-  // create summary structure for specific track conditions\r
-  //\r
-  SetMinMaxClITS();\r
-  SetMinMaxClITSFake();\r
-  SetMinMaxClITSCorr();\r
-  //\r
-  if (name==0 && title==0 && nlr==0) return;  // default dummy contructor\r
-  //\r
-  enum {kNBinRes=1000};\r
-  const double kMaxChi2(10),kMaxResRPhi=0.1, kMaxResZ=0.1,kMaxResPt=0.3;\r
-  //\r
-  TString strN = name, strT = title;\r
-  if (strN.IsNull()) strN = Form("TrSum%d",fgSumCounter);\r
-  if (strT.IsNull()) strT = strN;\r
-  fgSumCounter++;\r
-  //\r
-  if (fNITSLayers<1) {\r
-    fNITSLayers=KMCProbe::GetNITSLayers(); \r
-    if (fNITSLayers<1) {AliError("N ITS layer is not provided and not available from KMCProbe::GetNITSLayers()"); exit(1);}\r
-    AliInfo(Form("%s No N Layers provided, set %d",strN.Data(),fNITSLayers));\r
-  }\r
-  nlr = fNITSLayers;\r
-  //\r
-  TString nam,tit;\r
-  //\r
-  nam = Form("%s_mc_chi2",strN.Data());\r
-  tit = Form("%s MC #chi^{2}",strT.Data());\r
-  fHMCChi2 = new TH1F(nam.Data(),tit.Data(),kNBinRes,0,kMaxChi2);\r
-  fHMCChi2->GetXaxis()->SetTitle("#chi^{2}");\r
-  fHMCChi2->Sumw2();\r
-  //\r
-  nam = Form("%s_mc_DCArphi",strN.Data());\r
-  tit = Form("%s MC #DeltaDCA r#phi",strT.Data());\r
-  fHMCSigDCARPhi = new TH1F(nam.Data(),tit.Data(),kNBinRes,-kMaxResRPhi,kMaxResRPhi);\r
-  fHMCSigDCARPhi->GetXaxis()->SetTitle("#Delta r#phi");\r
-  fHMCSigDCARPhi->Sumw2();\r
-  //\r
-  nam = Form("%s_mc_DCAz",strN.Data());\r
-  tit = Form("%s MC #DeltaDCA Z",strT.Data());\r
-  fHMCSigDCAZ = new TH1F(nam.Data(),tit.Data(),kNBinRes,-kMaxResZ,kMaxResZ);\r
-  fHMCSigDCAZ->GetXaxis()->SetTitle("#Delta Z");\r
-  fHMCSigDCAZ->Sumw2();\r
-  //\r
-  nam = Form("%s_mc_pt",strN.Data());\r
-  tit = Form("%s MC $Deltap_{T}/p_{T}",strT.Data());\r
-  fHMCSigPt = new TH1F(nam.Data(),tit.Data(),2*kNBinRes,-kMaxResPt,kMaxResPt);\r
-  fHMCSigPt->GetXaxis()->SetTitle("#Deltap_{T}/p_{T}");\r
-  fHMCSigPt->Sumw2();\r
-  //\r
-  nam = Form("%s_n_cl",strN.Data());\r
-  tit = Form("%s N Clusters",strT.Data());\r
-  fHMCNCl = new TH2F(nam.Data(),tit.Data(),nlr,1,nlr+1,nlr,1,nlr+1);\r
-  fHMCNCl->GetXaxis()->SetTitle("N Clusters Tot");\r
-  fHMCNCl->GetYaxis()->SetTitle("N Clusters Fake");\r
-  fHMCNCl->Sumw2();\r
-  //\r
-  nam = Form("%s_fake_cl",strN.Data());\r
-  tit = Form("%s Fake Clusters",strT.Data());\r
-  fHMCFakePatt = new TH1F(nam.Data(),tit.Data(),nlr,-0.5,nlr-0.5);\r
-  fHMCFakePatt->GetXaxis()->SetTitle("Fake clusters pattern");\r
-  fHMCFakePatt->Sumw2();\r
-  //\r
-}\r
-\r
-//____________________________________________________________________________\r
-KMCTrackSummary::~KMCTrackSummary()\r
-{\r
-  if (fHMCChi2)         delete fHMCChi2;\r
-  if (fHMCSigDCARPhi)   delete fHMCSigDCARPhi;\r
-  if (fHMCSigDCAZ)      delete fHMCSigDCAZ;\r
-  if (fHMCSigPt)        delete fHMCSigPt;\r
-  if (fHMCNCl)          delete fHMCNCl;\r
-  if (fHMCFakePatt)     delete fHMCFakePatt;\r
-}\r
-\r
-\r
-//____________________________________________________________________________\r
-void KMCTrackSummary::Add(const KMCTrackSummary* src, double scl)\r
-{\r
-  if (fHMCChi2)         fHMCChi2->Add(src->fHMCChi2,scl);\r
-  if (fHMCSigDCARPhi)   fHMCSigDCARPhi->Add(src->fHMCSigDCARPhi,scl);\r
-  if (fHMCSigDCAZ)      fHMCSigDCAZ->Add(src->fHMCSigDCAZ,scl);\r
-  if (fHMCSigPt)        fHMCSigPt->Add(src->fHMCSigPt,scl);\r
-  if (fHMCNCl)          fHMCNCl->Add(src->fHMCNCl,scl);\r
-  if (fHMCFakePatt)     fHMCFakePatt->Add(src->fHMCFakePatt,scl);\r
-  fCountAcc += src->fCountAcc;\r
-  fUpdCalls += src->fUpdCalls;\r
-}\r
-\r
-//____________________________________________________________________________\r
-void KMCTrackSummary::PrependTNamed(TNamed* obj, const char* nm, const char* tit)\r
-{\r
-  // prepend  name, title by this prefix\r
-  TString name = obj->GetName(),title = obj->GetTitle();\r
-  name.Prepend(nm); title.Prepend(tit);\r
-  obj->SetNameTitle(name.Data(),title.Data());\r
-  //\r
-}\r
-  \r
-//____________________________________________________________________________\r
-void KMCTrackSummary::SetNamePrefix(const char* pref)\r
-{\r
-  // prepend all names by this prefix\r
-  TString nmT,nmP = pref;\r
-  if (nmP.IsNull()) return;\r
-  nmP = Form("%s_",pref);\r
-  nmT = Form("%s ",pref);\r
-  PrependTNamed(this, nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCChi2,       nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCSigDCARPhi, nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCSigDCAZ,    nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCSigPt,      nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCNCl,        nmP.Data(), nmT.Data());\r
-  PrependTNamed(fHMCFakePatt,   nmP.Data(), nmT.Data());\r
-  //  \r
-}\r
-\r
-//____________________________________________________________________________\r
-Bool_t KMCTrackSummary::CheckTrack(KMCProbe* trc)\r
-{\r
-  // check if the track satisfies to selection conditions\r
-  fCountTot++;\r
-  if (!trc) return kFALSE;\r
-  if (OutOfRange(trc->GetNITSHits(), fMinMaxClITS)) return kFALSE;\r
-  if (OutOfRange(trc->GetNFakeITSHits(), fMinMaxClITSFake)) return kFALSE;\r
-  if (OutOfRange(trc->GetNITSHits()-trc->GetNFakeITSHits(), fMinMaxClITSCorr)) return kFALSE;\r
-  //\r
-  // check layer patterns if requested\r
-  UInt_t patt  = trc->GetHitsPatt();\r
-  UInt_t pattF = trc->GetFakesPatt();\r
-  UInt_t pattC = patt&(~pattF);    // correct hits\r
-  // is there at least one hit in each of requested layer groups?\r
-  for (int ip=fPattITS.GetSize();ip--;)     if (!CheckPattern(patt,fPattITS[ip])) return kFALSE;\r
-  // is there at least one fake in any of requested layer groups?\r
-  for (int ip=fPattITSFakeExcl.GetSize();ip--;) if (CheckPattern(pattF,fPattITSFakeExcl[ip])) return kFALSE;\r
-  // is there at least one correct hit in each of requested layer groups?\r
-  for (int ip=fPattITSCorr.GetSize();ip--;) if (!CheckPattern(pattC,fPattITSCorr[ip])) return kFALSE;\r
-  //\r
-  fCountAcc++;\r
-  return kTRUE;\r
-}\r
-\r
-//____________________________________________________________________________\r
-void KMCTrackSummary::AddTrack(KMCProbe* trc)\r
-{\r
-  // fill track info\r
-  if (!CheckTrack(trc)) return;\r
-  //\r
-  fHMCChi2->Fill(trc->GetNormChi2(kFALSE));\r
-  fHMCSigDCARPhi->Fill(trc->GetY());\r
-  fHMCSigDCAZ->Fill(trc->GetZ());\r
-  if (fRefProbe.Pt()>0) fHMCSigPt->Fill( trc->Pt()/fRefProbe.Pt()-1.);\r
-  //  printf("Pts: %.3f %.3f -> %.3f\n",trc->Pt(),fRefProbe.Pt(),trc->Pt()/fRefProbe.Pt()-1.);\r
-  //  trc->Print("l");\r
-  //  fRefProbe.Print("l");\r
-  fHMCNCl->Fill(trc->GetNITSHits(),trc->GetNFakeITSHits());\r
-  for (int i=trc->GetNITSLayers();i--;) if (trc->IsHitFake(i)) fHMCFakePatt->Fill(i);\r
-  //\r
-}\r
-\r
-//____________________________________________________________________________\r
-UInt_t KMCTrackSummary::Bits(Bool_t l0, Bool_t l1, Bool_t l2, Bool_t l3, Bool_t l4, Bool_t l5, Bool_t l6, Bool_t l7,Bool_t  l8, Bool_t l9,\r
-                         Bool_t l10,Bool_t l11,Bool_t l12,Bool_t l13,Bool_t l14,Bool_t l15,Bool_t l16,Bool_t l17,Bool_t l18,Bool_t l19,\r
-                         Bool_t l20,Bool_t l21,Bool_t l22,Bool_t l23,Bool_t l24,Bool_t l25,Bool_t l26,Bool_t l27,Bool_t l28,Bool_t l29,\r
-                         Bool_t l30,Bool_t l31)\r
-{\r
-  // create corresponding bit pattern\r
-  UInt_t patt = 0;\r
-  if (l0 ) patt |= (0x1<<0);    if (l1 ) patt |= (0x1<<1);   if (l2 ) patt |= (0x1<<2);\r
-  if (l3 ) patt |= (0x1<<3);    if (l4 ) patt |= (0x1<<4);   if (l5 ) patt |= (0x1<<5);\r
-  if (l6 ) patt |= (0x1<<6);    if (l7 ) patt |= (0x1<<7);   if (l8 ) patt |= (0x1<<8);\r
-  if (l9 ) patt |= (0x1<<9);    if (l10) patt |= (0x1<<10);  if (l11) patt |= (0x1<<11);\r
-  if (l12) patt |= (0x1<<12);   if (l13) patt |= (0x1<<13);  if (l14) patt |= (0x1<<14);\r
-  if (l15) patt |= (0x1<<15);   if (l16) patt |= (0x1<<16);  if (l17) patt |= (0x1<<17);\r
-  if (l18) patt |= (0x1<<18);   if (l19) patt |= (0x1<<19);  if (l20) patt |= (0x1<<20);\r
-  if (l21) patt |= (0x1<<21);   if (l22) patt |= (0x1<<22);  if (l23) patt |= (0x1<<23);\r
-  if (l24) patt |= (0x1<<24);   if (l25) patt |= (0x1<<25);  if (l26) patt |= (0x1<<26);\r
-  if (l27) patt |= (0x1<<27);   if (l28) patt |= (0x1<<28);  if (l29) patt |= (0x1<<29);\r
-  if (l30) patt |= (0x1<<30);   if (l31) patt |= (0x1<<31);   \r
-  return patt;\r
-}\r
-\r
-//__________________________________________________________________________\r
-void KMCTrackSummary::Print(Option_t* ) const\r
-{\r
-  printf("%s: summary for track M=%5.3f pT: %6.3f eta: %.2f\n", GetName(),\r
-        fRefProbe.GetMass(),fRefProbe.Pt(), fRefProbe.Eta());\r
-  printf("Cuts on NCl ITS: Tot: %2d - %2d Fake: %2d - %2d Corr: %2d - %2d\n",\r
-        fMinMaxClITS[0],fMinMaxClITS[1], \r
-        fMinMaxClITSFake[0],fMinMaxClITSFake[1],\r
-        fMinMaxClITSCorr[0],fMinMaxClITSCorr[1]);\r
-  //\r
-  int nlr = fNITSLayers;\r
-  if (fPattITS.GetSize()) {\r
-    printf("Require at least 1 hit in groups: ");\r
-    printf("Hits obligatory in groups: ");\r
-    for (int i=fPattITS.GetSize();i--;) {\r
-      UInt_t pat = (UInt_t)fPattITS[i];\r
-      printf("[");\r
-      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);\r
-      printf("] ");\r
-    }\r
-    printf("\n");\r
-  }\r
-  //\r
-  if (fPattITSFakeExcl.GetSize()) {\r
-    printf("Fake hit forbidden in groups    : ");\r
-    for (int i=fPattITSFakeExcl.GetSize();i--;) {\r
-      UInt_t pat = (UInt_t)fPattITSFakeExcl[i];\r
-      printf("[");\r
-      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);\r
-      printf("] ");\r
-    }\r
-    printf("\n");\r
-  }\r
-  //\r
-  if (fPattITSCorr.GetSize()) {\r
-    printf("Correct hit obligatory in groups: ");\r
-    for (int i=fPattITSCorr.GetSize();i--;) {\r
-      UInt_t pat = (UInt_t)fPattITSCorr[i];\r
-      printf("[");\r
-      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);\r
-      printf("] ");\r
-    }\r
-    printf("\n");\r
-  }\r
-  //  \r
-  printf("Entries: Tot: %.4e Acc: %.4e -> Eff: %.4f+-%.4f %.2e KMC updates\n",fCountTot,fCountAcc,GetEff(),GetEffErr(),GetUpdCalls());\r
-}\r
-\r
+#include "KMCDetector.h"
+#include <TMath.h>
+#include <TH1F.h>
+#include <TProfile.h>
+#include <TF1.h>
+#include <TMatrixD.h>
+#include <TGraph.h>
+#include <TAxis.h>
+#include <TFormula.h>
+#include <TCanvas.h>
+#include <TEllipse.h>
+#include <TText.h>
+#include <TRandom3.h>
+#include <TGraphErrors.h>
+#include <TStopwatch.h>
+
+/***********************************************************
+
+Fast Simulation tool for Inner Tracker Systems
+
+***********************************************************/
+
+
+#define RIDICULOUS 999999 // A ridiculously large resolution (cm) to flag a dead detector
+
+#define Luminosity    1.e27       // Luminosity of the beam (LHC HI == 1.e27, RHIC II == 8.e27 )
+#define SigmaD        6.0         // Size of the interaction diamond (cm) (LHC = 6.0 cm)
+#define dNdEtaMinB    1//950//660//950           // Multiplicity per unit Eta  (AuAu MinBias = 170, Central = 700)
+// #define dNdEtaCent    2300//15000 //1600//2300        // Multiplicity per unit Eta  (LHC at 5.5 TeV not known)
+
+#define CrossSectionMinB         8    // minB Cross section for event under study (PbPb MinBias ~ 8 Barns)
+#define AcceptanceOfTpcAndSi     1 //1//0.60 //0.35  // Assumed geometric acceptance (efficiency) of the TPC and Si detectors
+#define UPCBackgroundMultiplier  1.0   // Increase multiplicity in detector (0.0 to 1.0 * UPCRate ) (eg 1.0)
+#define OtherBackground          0.0   // Increase multiplicity in detector (0.0 to 1.0 * minBias)  (eg 0.0)
+#define EfficiencySearchFlag     2     // Define search method:
+                                       // -> ChiSquarePlusConfLevel = 2, ChiSquare = 1, Simple = 0.  
+
+#define PionMass                 0.139  // Mass of the Pion
+#define KaonMass                 0.498  // Mass of the Kaon
+#define D0Mass                   1.865  // Mass of the D0
+
+//TMatrixD *probKomb; // table for efficiency kombinatorics
+
+ClassImp(KMCProbe)
+
+Int_t    KMCProbe::fgNITSLayers = 0;
+Double_t KMCProbe::fgMissingHitPenalty = 2.;
+//__________________________________________________________________________
+KMCProbe& KMCProbe::operator=(const KMCProbe& src) 
+{
+  if (this!=&src) {
+    AliExternalTrackParam::operator=(src);
+    fMass = src.fMass;
+    fChi2 = src.fChi2;
+    fHits = src.fHits;
+    fFakes = src.fFakes;
+    fNHits = src.fNHits;
+    fNHitsITS = src.fNHitsITS;
+    fNHitsITSFake = src.fNHitsITSFake;
+    fInnLrCheck     = src.fInnLrCheck;
+    for (int i=kMaxITSLr;i--;) fClID[i] = src.fClID[i];
+  }
+  return *this;
+}
+
+//__________________________________________________________________________
+KMCProbe::KMCProbe(KMCProbe& src) 
+  : AliExternalTrackParam(src),
+    fMass(src.fMass),
+    fChi2(src.fChi2),
+    fHits(src.fHits),
+    fFakes(src.fFakes),
+    fNHits(src.fNHits),
+    fNHitsITS(src.fNHitsITS),
+    fNHitsITSFake(src.fNHitsITSFake),
+    fInnLrCheck(src.fInnLrCheck)
+{
+  for (int i=kMaxITSLr;i--;) fClID[i] = src.fClID[i];
+}
+
+//__________________________________________________________________________
+void KMCProbe::ResetCovMat()
+{
+  // reset errors
+  double *trCov  = (double*)GetCovariance();
+  double *trPars = (double*)GetParameter();
+  const double kLargeErr2Coord = 50*50;
+  const double kLargeErr2Dir = 0.6*0.6;
+  const double kLargeErr2PtI = 0.5*0.5;
+  for (int ic=15;ic--;) trCov[ic] = 0.;
+  trCov[kY2]   = trCov[kZ2]   = kLargeErr2Coord; 
+  trCov[kSnp2] = trCov[kTgl2] = kLargeErr2Dir;
+  trCov[kPtI2] = kLargeErr2PtI*trPars[kPtI]*trPars[kPtI];
+  //
+}
+
+//__________________________________________________________________________
+void KMCProbe::Print(Option_t* option) const
+{
+  printf("M=%.3f Chi2=%7.2f (Norm:%6.2f|%d) Hits: Total:%d ITS:%d ITSFakes:%d | Y:%+8.4f Z: %+8.4f |", 
+        fMass,fChi2,GetNormChi2(kTRUE),fInnLrCheck,fNHits,fNHitsITS,fNHitsITSFake, GetY(),GetZ());
+  for (int i=0;i<fgNITSLayers;i++) {
+    if (!IsHit(i)) printf(".");
+    else printf("%c",IsHitFake(i) ? '-':'+');
+  }
+  printf("|%s\n",IsKilled() ? " KILLED":"");
+  TString opt = option;
+  if (!opt.IsNull()) AliExternalTrackParam::Print(option);
+}
+
+//__________________________________________________________________________
+Int_t KMCProbe::Compare(const TObject* obj) const
+{
+  // compare to tracks
+  const KMCProbe* trc = (KMCProbe*) obj;
+  if (trc->IsKilled()) {
+    if (IsKilled()) return 0;
+    return -1;
+  }
+  else if (IsKilled()) return 1;
+  double chi2a = GetNormChi2(kTRUE);
+  double chi2b = trc->GetNormChi2(kTRUE);
+  if (chi2a<chi2b) return  -1;
+  if (chi2a>chi2b) return   1;
+  return 0;
+}
+
+//__________________________________________________________________________
+Bool_t KMCProbe::GetXatLabR(Double_t r,Double_t &x, Double_t bz, Int_t dir) const
+{
+  // Get local X of the track position estimated at the radius lab radius r. 
+  // The track curvature is accounted exactly
+  //
+  // The flag "dir" can be used to remove the ambiguity of which intersection to take (out of 2 possible)
+  // 0  - take the intersection closest to the current track position
+  // >0 - go along the track (increasing fX)
+  // <0 - go backward (decreasing fX)
+  //
+  // special case of R=0
+  if (r<kAlmost0) {x=0; return kTRUE;}
+
+  const double* pars = GetParameter();
+  const Double_t &fy=pars[0], &sn = pars[2];
+  //
+  double fx = GetX();
+  double crv = GetC(bz);
+  if (TMath::Abs(crv)<=kAlmost0) { // this is a straight track
+    if (TMath::Abs(sn)>=kAlmost1) { // || to Y axis
+      double det = (r-fx)*(r+fx);
+      if (det<0) return kFALSE;     // does not reach raduis r
+      x = fx;
+      if (dir==0) return kTRUE;
+      det = TMath::Sqrt(det);
+      if (dir>0) {                       // along the track direction
+       if (sn>0) {if (fy>det)  return kFALSE;} // track is along Y axis and above the circle
+       else      {if (fy<-det) return kFALSE;} // track is against Y axis amd belo the circle
+      }
+      else if(dir>0) {                                    // agains track direction
+       if (sn>0) {if (fy<-det) return kFALSE;} // track is along Y axis
+        else if (fy>det)  return kFALSE;        // track is against Y axis
+      }
+    }
+    else if (TMath::Abs(sn)<=kAlmost0) { // || to X axis
+      double det = (r-fy)*(r+fy);
+      if (det<0) return kFALSE;     // does not reach raduis r
+      det = TMath::Sqrt(det);
+      if (!dir) {
+       x = fx>0  ? det : -det;    // choose the solution requiring the smalest step
+       return kTRUE;
+      }
+      else if (dir>0) {                    // along the track direction
+       if      (fx > det) return kFALSE;  // current point is in on the right from the circle
+       else if (fx <-det) x = -det;       // on the left
+       else               x =  det;       // within the circle
+      }
+      else {                               // against the track direction
+       if      (fx <-det) return kFALSE;  
+       else if (fx > det) x =  det;
+       else               x = -det;
+      }
+    }
+    else {                                 // general case of straight line
+      double cs = TMath::Sqrt((1-sn)*(1+sn));
+      double xsyc = fx*sn-fy*cs;
+      double det = (r-xsyc)*(r+xsyc);
+      if (det<0) return kFALSE;    // does not reach raduis r
+      det = TMath::Sqrt(det);
+      double xcys = fx*cs+fy*sn;
+      double t = -xcys;
+      if (dir==0) t += t>0 ? -det:det;  // chose the solution requiring the smalest step
+      else if (dir>0) {                 // go in increasing fX direction. ( t+-det > 0)
+       if (t>=-det) t += -det;         // take minimal step giving t>0
+       else return kFALSE;             // both solutions have negative t
+      }
+      else {                            // go in increasing fx direction. (t+-det < 0)
+       if (t<det) t -= det;            // take minimal step giving t<0
+       else return kFALSE;             // both solutions have positive t
+      }
+      x = fx + cs*t;
+    }
+  }
+  else {                                 // helix
+    // get center of the track circle
+    double tR = 1./crv;   // track radius (for the moment signed)
+    double cs = TMath::Sqrt((1-sn)*(1+sn));
+    double x0 = fx - sn*tR;
+    double y0 = fy + cs*tR;
+    double r0 = TMath::Sqrt(x0*x0+y0*y0);
+    //    printf("Xc:%+e Yc:%+e\n",x0,y0);
+    //
+    if (r0<=kAlmost0) {
+      AliDebug(2,Form("r0 = %f",r0));
+      return kFALSE;
+    }            // the track is concentric to circle
+    tR = TMath::Abs(tR);
+    double tR2r0 = tR/r0;
+    double g = 0.5*(r*r/(r0*tR) - tR2r0 - 1./tR2r0);
+    double det = (1.-g)*(1.+g);
+    if (det<0) {
+      AliDebug(2,Form("g=%f tR=%f r0=%f\n",g,tR, r0));
+      return kFALSE;
+    }         // does not reach raduis r
+    det = TMath::Sqrt(det);
+    //
+    // the intersection happens in 2 points: {x0+tR*C,y0+tR*S} 
+    // with C=f*c0+-|s0|*det and S=f*s0-+c0 sign(s0)*det
+    // where s0 and c0 make direction for the circle center (=x0/r0 and y0/r0)
+    //
+    double tmp = 1.+g*tR2r0;
+    x = x0*tmp; 
+    double y = y0*tmp;
+    if (TMath::Abs(y0)>kAlmost0) { // when y0==0 the x,y is unique
+      double dfx = tR2r0*TMath::Abs(y0)*det;
+      double dfy = tR2r0*x0*TMath::Sign(det,y0);
+      if (dir==0) {                    // chose the one which corresponds to smallest step 
+       double delta = (x-fx)*dfx-(y-fy)*dfy; // the choice of + in C will lead to smaller step if delta<0
+       if (delta<0) x += dfx;
+       else         x -= dfx;
+      }
+      else if (dir>0) {  // along track direction: x must be > fx
+       x -= dfx; // try the smallest step (dfx is positive)
+       if (x<fx && (x+=dfx+dfx)<fx) return kFALSE;
+      }
+      else { // backward: x must be < fx
+       x += dfx; // try the smallest step (dfx is positive)
+       if (x>fx && (x-=dfx+dfx)>fx) return kFALSE;
+      }
+    }
+    else { // special case: track touching the circle just in 1 point
+      if ( (dir>0&&x<fx) || (dir<0&&x>fx) ) return kFALSE; 
+    }
+  }
+  //
+  return kTRUE;
+}
+
+//____________________________________
+Bool_t KMCProbe::PropagateToR(double r, double b, int dir) 
+{
+  // go to radius R
+  //
+  double xR = 0;
+  double rr = r*r;
+  int iter = 0;
+  const double kTiny = 1e-4;
+  while(1) {
+    if (!GetXatLabR(r ,xR, b, dir)) {
+      //      printf("Track with pt=%f cannot reach radius %f\n",Pt(),r);
+      //      Print("l");
+      return kFALSE;
+    }
+    
+    if (!PropagateTo(xR, b)) {
+      if (AliLog::GetGlobalDebugLevel()>2) {
+       printf("Failed to propagate to X=%f for R=%f\n",xR,r); 
+       Print("l"); 
+      }
+      return kFALSE;
+    }
+    double rcurr2 = xR*xR + GetY()*GetY();
+    if (TMath::Abs(rcurr2-rr)<kTiny || rr<kAlmost0) return kTRUE;
+    //
+    // two radii correspond to this X...
+    double pos[3]; GetXYZ(pos);
+    double phi = TMath::ATan2(pos[1],pos[0]);
+    if (!Rotate(phi)) {
+      if (AliLog::GetGlobalDebugLevel()>2) {
+       printf("Failed to rotate to %f to propagate to R=%f\n",phi,r); 
+       Print("l"); 
+      }
+      return kFALSE;
+    }
+    if (++iter>8) {
+      if (AliLog::GetGlobalDebugLevel()>2) {
+       printf("Failed to propagate to R=%f after %d steps\n",r,iter); 
+       Print("l"); 
+      }
+      return kFALSE;
+    }
+  } 
+  return kTRUE;
+}
+
+
+//__________________________________________________________________________
+Bool_t KMCProbe::CorrectForMeanMaterial(const KMCLayer* lr, Bool_t inward)
+{
+  //  printf("before at r=%.1f p=%.4f\n",lr->fR, P());
+  if (AliExternalTrackParam::CorrectForMeanMaterial(lr->fx2X0, inward ? lr->fXRho : -lr->fXRho, GetMass() , kTRUE)) {
+    //  printf("after  at r=%.1f p=%.4f\n",lr->fR, P());
+    return kTRUE;
+  }
+  AliDebug(2,Form("Failed to apply material correction, X/X0=%.4f", lr->fx2X0));
+  if (AliLog::GetGlobalDebugLevel()>1) Print();
+  return kFALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+ClassImp(KMCCluster)
+
+//_________________________________________________________________________
+KMCCluster::KMCCluster(KMCCluster &src) 
+: TObject(src),
+  fY(src.fY),fZ(src.fZ),fX(src.fX),fPhi(src.fPhi)
+{}
+
+//__________________________________________________________________________
+KMCCluster& KMCCluster::operator=(const KMCCluster& src) 
+{
+  if (this!=&src) {
+    TObject::operator=(src);
+    fY = src.fY;
+    fZ = src.fZ;
+    fX = src.fX;
+    fPhi = src.fPhi;
+  }
+  return *this;
+}
+
+//_________________________________________________________________________
+void KMCCluster::Print(Option_t *) const 
+{
+  printf(" Local YZ = (%3.4lf,%3.4lf) | X=%3.4lf  phi: %+.3f %s\n",fY,fZ,fX,fPhi,IsKilled()?"Killed":""); 
+}
+
+/////////////////////////////////////////////////////////////////////////////
+ClassImp(KMCLayer)
+
+Double_t KMCLayer::fgDefEff = 1.0;
+//__________________________________________________________________________
+KMCLayer::KMCLayer(char *name) : 
+  TNamed(name,name),fR(0),fx2X0(0),fPhiRes(0),fZRes(0),fEff(0),fIsDead(kFALSE),fType(-1),fActiveID(-1),fSig2EstD(999),fSig2EstZ(999),
+  fClCorr(),fClMC(),fClBg("KMCCluster",5), fTrCorr(), fTrMC("KMCProbe",5)
+{
+  Reset();
+}
+
+//__________________________________________________________________________
+void KMCLayer::Reset() 
+{
+  fTrCorr.Reset();
+  fClCorr.Reset();
+  ResetMC();
+  fSig2EstD = fSig2EstZ = 999;
+  //
+}
+
+//__________________________________________________________________________
+KMCProbe* KMCLayer::AddMCTrack(KMCProbe* src) 
+{
+  int ntr = GetNMCTracks(); 
+  KMCProbe* prb = 0;
+  if (src) prb = new(fTrMC[ntr]) KMCProbe(*src);
+  else     prb = new(fTrMC[ntr]) KMCProbe();
+  if (!IsDead()) prb->ResetHit(GetActiveID());
+  return prb;
+}
+
+//__________________________________________________________________________
+void KMCLayer::Print(Option_t *opt) const
+{
+  printf("Lr%3d(A%3d) %10s R=%5.1f X2X0=%.3f XRho=%.3f SigY=%.4f SigZ=%.4f Eff:%4.2f\n",GetUniqueID(),fActiveID,GetName(), fR, fx2X0,fXRho,fPhiRes,fZRes,fEff);
+  TString opts = opt; opts.ToLower();
+  if (opts.Contains("c")) {
+    printf("Clusters: MC: %+7.4f:%+7.4f Ideal: %+7.4f:%+7.4f  NBgCl: %3d NTrMC: %4d\n",fClMC.fY,fClMC.fZ, fClCorr.fY,fClCorr.fZ, GetNBgClusters(),GetNMCTracks());
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+Double_t KMCDetector::fgVtxConstraint[2]={-1,-1};
+
+ClassImp(KMCDetector)
+KMCDetector::KMCDetector() :
+TNamed("test_detector","detector"),
+  fNLayers(0),
+  fNActiveLayers(0),
+  fNActiveITSLayers(0),
+  fLastActiveLayer(-1),
+  fLastActiveITSLayer(-1),
+  fLastActiveLayerTracked(-1),
+  fBFieldG(5.),
+  fLhcUPCscale(1.0),    
+  fIntegrationTime(0.02), // in ms
+  fConfLevel(0.0027),      // 0.27 % -> 3 sigma confidence
+  fAvgRapidity(0.45),      // Avg rapidity, MCS calc is a function of crossing angle
+  fParticleMass(0.140),    // Standard: pion mass 
+  fMaxRadiusSlowDet(10.),
+  fAtLeastCorr(-1),     // if -1, then correct hit on all ITS layers
+  fAtLeastFake(1),       // if at least x fakes, track is considered fake ...
+  fdNdEtaCent(2300),
+  fMaxChi2Cl(25.),
+  fMaxNormChi2NDF(5.),
+  fMinITSHits(4),
+//
+  fMaxChi2ClSQ(4.), // precalulated internally
+  fMaxSeedToPropagate(300),
+//
+  fUseBackground(kFALSE),
+  fBgYMin(1e6),fBgYMax(-1e6),fBgZMin(1e6),fBgZMax(-1e6),
+  fBgYMinTr(100),fBgYMaxTr(100),fBgZMinTr(100),fBgZMaxTr(100),fNBgLimits(0),
+  fDensFactorEta(1.),
+//
+  fUpdCalls(0),
+  fHMCLrResidRPhi(0),
+  fHMCLrResidZ(0),
+  fHMCLrChi2(0),
+  fPattITS(0)
+{
+  //
+  // default constructor
+  //
+  //  fLayers = new TObjArray();
+  RequireMaxChi2Cl(fMaxChi2Cl); // just to precalulate default square
+}
+
+KMCDetector::KMCDetector(char *name, char *title)
+  : TNamed(name,title),
+    fNLayers(0),
+    fNActiveLayers(0),
+    fNActiveITSLayers(0),
+    fLastActiveLayer(-1),
+    fLastActiveITSLayer(-1),    
+    fLastActiveLayerTracked(-1),
+    fBFieldG(5.0),
+    fLhcUPCscale(1.0),
+    fIntegrationTime(0.02),  // in ms
+    fConfLevel(0.0027),      // 0.27 % -> 3 sigma confidence
+    fAvgRapidity(0.45),      // Avg rapidity, MCS calc is a function of crossing angle
+    fParticleMass(0.140),     // Standard: pion mass
+    fMaxRadiusSlowDet(10.),
+    fAtLeastCorr(-1),     // if -1, then correct hit on all ITS layers
+    fAtLeastFake(1),       // if at least x fakes, track is considered fake ...
+    fdNdEtaCent(2300),
+    fMaxChi2Cl(9.),
+    fMaxNormChi2NDF(5.),
+    fMinITSHits(4),
+    //
+    fMaxChi2ClSQ(3.), // precalulated internally
+    fMaxSeedToPropagate(50),
+    //
+    fUseBackground(kFALSE),
+    fBgYMin(1e6),fBgYMax(-1e6),fBgZMin(1e6),fBgZMax(-1e6),
+    fBgYMinTr(100),fBgYMaxTr(100),fBgZMinTr(100),fBgZMaxTr(100),fNBgLimits(0),
+    fDensFactorEta(1.),
+    //
+    fUpdCalls(0),
+    fHMCLrResidRPhi(0),
+    fHMCLrResidZ(0),
+    fHMCLrChi2(0),
+    fPattITS(0)
+{
+  //
+  // default constructor, that set the name and title
+  //
+  //  fLayers = new TObjArray();
+}
+KMCDetector::~KMCDetector() { // 
+  // virtual destructor
+  //
+  //  delete fLayers;
+}
+
+void KMCDetector::InitMCWatchHistos()
+{
+  // init utility histos used for MC tuning
+  enum {kNBinRes=1000};
+  const double kMaxResidRPhi=1.0,kMaxResidZ=1.0,kMaxChi2=50;
+  int nlr = fNActiveITSLayers;
+  TString nam = "mc_residrhi";
+  TString tit = "MC $Delta Cl-Tr R#phi";
+  fHMCLrResidRPhi = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxResidRPhi,nlr,-0.5,nlr-0.5);
+  fHMCLrResidRPhi->GetXaxis()->SetTitle("cl-tr #Delta r#phi");
+  fHMCLrResidRPhi->Sumw2();
+    //
+  nam = "mc_residz";
+  tit = "MC $Delta Cl-Tr Z";
+  fHMCLrResidZ = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxResidZ,nlr,-0.5,nlr-0.5);
+  fHMCLrResidZ->GetXaxis()->SetTitle("cl-tr #Delta z");
+  fHMCLrResidZ->Sumw2();
+    //
+  nam = "mc_chi2";
+  tit = "MC #chi^{2} Cl-Tr Z";
+  fHMCLrChi2 = new TH2F(nam.Data(),tit.Data(),kNBinRes,-kMaxResidRPhi,kMaxChi2,nlr,-0.5,nlr-0.5);
+  fHMCLrChi2->GetXaxis()->SetTitle("cl-tr #chi^{2}");
+  fHMCLrChi2->Sumw2();
+  //
+  SetBit(kUtilHisto);
+}
+
+
+void KMCDetector::AddLayer(char *name, Float_t radius, Float_t x2X0, Float_t xrho, Float_t phiRes, Float_t zRes, Float_t eff) {
+  //
+  // Add additional layer to the list of layers (ordered by radius)
+  // 
+
+  KMCLayer *newLayer = (KMCLayer*) fLayers.FindObject(name);
+
+  if (!newLayer) {
+    newLayer = new KMCLayer(name);
+    newLayer->fR = radius;
+    newLayer->fx2X0 = x2X0;
+    newLayer->fXRho  = xrho;
+    newLayer->fPhiRes = phiRes;
+    newLayer->fZRes = zRes;
+    eff = TMath::Min(1.f,eff);
+    newLayer->fEff = eff <0 ? KMCLayer::GetDefEff() : eff;
+    newLayer->fActiveID = -2;
+    TString lname = name;
+    newLayer->fType = KMCLayer::kTypeNA;
+    if      (lname.Contains("tpc")) newLayer->fType = KMCLayer::kTPC;
+    else if (lname.Contains("its")) newLayer->fType = KMCLayer::kITS;
+    if (lname.Contains("vertex")) newLayer->SetBit(KMCLayer::kBitVertex);
+    //
+    if (newLayer->fType==KMCLayer::kTypeNA) printf("Attention: the layer %s has undefined type\n",name);
+    //
+    newLayer->fIsDead =  (newLayer->fPhiRes==RIDICULOUS && newLayer->fZRes==RIDICULOUS);
+    //
+    if (fLayers.GetEntries()==0) 
+      fLayers.Add(newLayer);
+    else {
+      //
+      for (Int_t i = 0; i<fLayers.GetEntries(); i++) {
+       KMCLayer *l = (KMCLayer*)fLayers.At(i);
+       if (radius<l->fR) { fLayers.AddBefore(l,newLayer); break; }
+         if (radius>l->fR && (i+1)==fLayers.GetEntries() ) fLayers.Add(newLayer); // even bigger then last one
+      }
+      //
+    }
+    //
+    ClassifyLayers();
+    //
+  } else {
+    printf("Layer with the name %s does already exist\n",name);
+  }
+}
+
+//____________________________________________________________
+void KMCDetector::ClassifyLayers()
+{
+  // assign active Id's, etc
+  fLastActiveLayer = -1;
+  fLastActiveITSLayer = -1;
+  fNActiveLayers = 0;
+  fNActiveITSLayers = 0;
+  //
+  int nl = GetNLayers();
+  for (int il=0;il<nl;il++) {
+    KMCLayer* lr = GetLayer(il);
+    lr->SetUniqueID(il);
+    if (!lr->IsDead()) {
+      fLastActiveLayer = il; 
+      lr->fActiveID = fNActiveLayers++;
+      if (lr->IsITS()) {
+       fLastActiveITSLayer = il;
+       fNActiveITSLayers++;
+      }
+    }
+  }
+  //
+  KMCProbe::SetNITSLayers(fNActiveITSLayers);
+}
+
+//____________________________________________________________
+void KMCDetector::KillLayer(char *name) {
+  //
+  // Marks layer as dead. Contribution only by Material Budget
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot mark as dead\n",name);
+  else {
+     tmp->fPhiRes = 999999;
+     tmp->fZRes = 999999;
+     tmp->fIsDead = kTRUE;
+     ClassifyLayers();
+  }
+}
+
+void KMCDetector::SetRadius(char *name, Float_t radius) {
+  //
+  // Set layer radius [cm]
+  //
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  //
+  if (!tmp) {
+    printf("Layer %s not found - cannot set radius\n",name);
+  } else {
+      
+    Float_t tmpRadL  = tmp->fx2X0;
+    Float_t tmpPhiRes = tmp->fPhiRes;
+    Float_t tmpZRes = tmp->fZRes;
+    Float_t tmpXRho = tmp->fXRho;
+    RemoveLayer(name); // so that the ordering is correct
+    AddLayer(name,radius,tmpRadL,tmpXRho,tmpPhiRes,tmpZRes);
+  }
+}
+
+Float_t KMCDetector::GetRadius(char *name) {
+  //
+  // Return layer radius [cm]
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot get radius\n",name);
+  else 
+    return tmp->fR;
+
+  return 0;
+}
+
+void KMCDetector::SetRadiationLength(char *name, Float_t x2X0) {
+  //
+  // Set layer material [cm]
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot set layer material\n",name);
+  else {
+    tmp->fx2X0 = x2X0;
+  }
+}
+
+Float_t KMCDetector::GetRadiationLength(char *name) {
+  //
+  // Return layer radius [cm]
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot get layer material\n",name);
+  else 
+    return tmp->fx2X0;
+    
+  return 0;
+  
+}
+
+void KMCDetector::SetResolution(char *name, Float_t phiRes, Float_t zRes) {
+  //
+  // Set layer resolution in [cm]
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot set resolution\n",name);
+  else {
+    tmp->fPhiRes = phiRes;
+    tmp->fZRes = zRes;
+    tmp->fIsDead = (zRes==RIDICULOUS && phiRes==RIDICULOUS);
+    ClassifyLayers();
+  }
+}
+
+Float_t KMCDetector::GetResolution(char *name, Int_t axis) {
+  //
+  // Return layer resolution in [cm]
+  // axis = 0: resolution in rphi
+  // axis = 1: resolution in z
+  //
+
+  KMCLayer *tmp = GetLayer(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot get resolution\n",name);
+  else {
+    if (axis==0) return tmp->fPhiRes;
+    if (axis==1) return tmp->fZRes;
+    printf("error: axis must be either 0 or 1 (rphi or z axis)\n");
+  }
+  return 0;
+}
+
+void KMCDetector::SetLayerEfficiency(char *name, Float_t eff) {
+  //
+  // Set layer efficnecy (prop that his is missed within this layer) 
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot set layer efficiency\n",name);
+  else {
+    tmp->fEff = eff;
+  }
+}
+
+Float_t KMCDetector::GetLayerEfficiency(char *name) {
+  //
+  // Get layer efficnecy (prop that his is missed within this layer) 
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot get layer efficneicy\n",name);
+  else 
+    return tmp->fEff;
+    
+  return 0;
+  
+}
+
+void KMCDetector::RemoveLayer(char *name) {
+  //
+  // Removes a layer from the list
+  //
+
+  KMCLayer *tmp = (KMCLayer*) fLayers.FindObject(name);
+  if (!tmp) 
+    printf("Layer %s not found - cannot remove it\n",name);
+  else {
+    fLayers.Remove(tmp);
+    ClassifyLayers();
+  }
+}
+
+
+void KMCDetector::PrintLayout() {
+  //
+  // Prints the detector layout
+  //
+
+  printf("Detector %s: \"%s\"\n",GetName(),GetTitle());
+  
+  if (fLayers.GetEntries()>0) 
+    printf("  Name \t\t r [cm] \t  X0 \t  phi & z res [um]\n");
+
+  KMCLayer *tmp = 0;
+  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {
+    tmp = (KMCLayer*)fLayers.At(i);
+  
+    // don't print all the tpc layers
+    TString name(tmp->GetName());
+    if (name.Contains("tpc") && (!name.Contains("tpc_0")) ) continue;
+
+    printf("%d. %s \t %03.2f   \t%1.4f\t  ",i,
+          tmp->GetName(), tmp->fR, tmp->fx2X0);
+    if (tmp->fPhiRes==RIDICULOUS) 
+      printf("  -  ");
+    else
+      printf("%3.0f   ",tmp->fPhiRes*10000);
+    if (tmp->fZRes==RIDICULOUS) 
+      printf("  -\n");
+    else
+      printf("%3.0f\n",tmp->fZRes*10000);
+  }
+}
+
+void KMCDetector::PlotLayout(Int_t plotDead) {
+  //
+  // Plots the detector layout in Front view
+  //
+
+  Double_t x0=0, y0=0;
+
+  TGraphErrors *gr = new TGraphErrors();
+  gr->SetPoint(0,0,0);
+  KMCLayer *lastLayer = (KMCLayer*)fLayers.At(fLayers.GetEntries()-1);  Double_t maxRad = lastLayer->fR;
+  gr->SetPointError(0,maxRad,maxRad);
+  gr->Draw("APE");
+  
+
+  KMCLayer *tmp = 0;
+  for (Int_t i = fLayers.GetEntries()-1; i>=0; i--) {
+    tmp = (KMCLayer*)fLayers.At(i);
+  
+
+    Double_t txtpos = tmp->fR;
+    if ((tmp->IsDead())) txtpos*=-1; //
+    TText *txt = new TText(x0,txtpos,tmp->GetName());
+    txt->SetTextSizePixels(5); txt->SetTextAlign(21);
+    if (!tmp->IsDead() || plotDead) txt->Draw();
+
+    TEllipse *layEl = new TEllipse(x0,y0,tmp->fR);
+    //  layEl->SetFillColor(5);
+    layEl->SetFillStyle(5001);
+    layEl->SetLineStyle(tmp->IsDead()+1); // dashed if not active
+    layEl->SetLineColor(4);
+    TString name(tmp->GetName());
+    if (!tmp->IsDead()) layEl->SetLineWidth(2);
+    if (name.Contains("tpc") )  layEl->SetLineColor(29);
+
+    if (!tmp->IsDead() || plotDead) layEl->Draw();
+  
+  }
+
+}
+
+
+
+void KMCDetector::AddTPC(Float_t phiResMean, Float_t zResMean, Int_t skip) {
+  //
+  // Emulates the TPC
+  // 
+  // skip=1: Use every padrow, skip=2: Signal in every 2nd padrow 
+
+
+  AddLayer((char*)"IFCtpc",   77.8,0.01367, 0); // Inner Field cage (RS: set correct xrho for eloss)
+  
+  // % Radiation Lengths ... Average per TPC row  (i.e. total/159 )
+  Float_t x2X0PerRow = 0.000036;
+  
+  Float_t tpcInnerRadialPitch  =    0.75 ;    // cm
+  Float_t tpcMiddleRadialPitch =    1.0  ;    // cm
+  Float_t tpcOuterRadialPitch  =    1.5  ;    // cm
+  //  Float_t tpcInnerPadWidth     =    0.4  ;    // cm
+  //  Float_t tpcMiddlePadWidth    =    0.6   ;   // cm
+  //  Float_t tpcOuterPadWidth     =    0.6   ;   // cm
+  Float_t innerRows            =   63 ;
+  Float_t middleRows           =   64  ;
+  Float_t outerRows            =   32  ;
+  Float_t tpcRows            =   (innerRows + middleRows + outerRows) ;
+  Float_t rowOneRadius         =   85.2  ;    // cm
+  Float_t row64Radius          =  135.1  ;    // cm
+  Float_t row128Radius         =  199.2  ;    // cm                       
+  for ( Int_t k = 0 ; k < tpcRows ; k++ ) {
+    
+    Float_t rowRadius =0;
+    if (k<innerRows) 
+      rowRadius =  rowOneRadius + k*tpcInnerRadialPitch ;
+    else if ( k>=innerRows && k<(innerRows+middleRows) )
+      rowRadius =  row64Radius + (k-innerRows+1)*tpcMiddleRadialPitch ;
+    else if (k>=(innerRows+middleRows) && k<tpcRows )
+      rowRadius = row128Radius + (k-innerRows-middleRows+1)*tpcOuterRadialPitch ;
+
+    if ( k%skip == 0 )
+      AddLayer(Form("tpc_%d",k),rowRadius,x2X0PerRow,0, phiResMean,zResMean);    
+    else 
+      AddLayer(Form("tpc_%d",k),rowRadius,x2X0PerRow,0); // non "active" row
+    
+  
+  }
+}
+
+void KMCDetector::RemoveTPC() {
+
+  // flag as dead, although resolution is ok ... makes live easier in the prints ... ;-)
+  KMCLayer *tmp = 0;
+  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {
+    tmp = (KMCLayer*)fLayers.At(i);  
+    TString name(tmp->GetName());
+    if (name.Contains("tpc")) { RemoveLayer((char*)name.Data()); i--; }
+  }
+  RemoveLayer((char*)"IFC");
+  
+}
+
+
+Double_t KMCDetector::ThetaMCS ( Double_t mass, Double_t x2X0, Double_t momentum ) const
+{
+  //
+  // returns the Multiple Couloumb scattering angle (compare PDG boolet, 2010, equ. 27.14)
+  //
+
+  Double_t beta  =  momentum / TMath::Sqrt(momentum*momentum+mass*mass)  ;
+  Double_t theta =  0.0 ;    // Momentum and mass in GeV
+  // if ( RadLength > 0 ) theta  =  0.0136 * TMath::Sqrt(RadLength) / ( beta * momentum );
+  if ( x2X0 > 0 ) theta  =  0.0136 * TMath::Sqrt(x2X0) / ( beta * momentum ) * (1+0.038*TMath::Log(x2X0)) ;
+  return (theta) ;
+}
+
+
+Double_t KMCDetector::ProbGoodHit ( Double_t radius, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) 
+{
+  // Based on work by Howard Wieman: http://rnc.lbl.gov/~wieman/GhostTracks.htm 
+  // and http://rnc.lbl.gov/~wieman/HitFinding2D.htm
+  // This is the probability of getting a good hit using 2D Gaussian distribution function and infinite search radius
+  Double_t sx, sy, goodHit ;
+  sx = 2 * TMath::Pi() *  searchRadiusRPhi * searchRadiusRPhi * HitDensity(radius) ;
+  sy = 2 * TMath::Pi() *  searchRadiusZ    * searchRadiusZ    * HitDensity(radius) ;
+  goodHit =  TMath::Sqrt(1./((1+sx)*(1+sy)))  ;
+  return ( goodHit ) ;
+}
+
+
+Double_t KMCDetector::ProbGoodChiSqHit ( Double_t radius, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) 
+{
+  // Based on work by Victor Perevoztchikov and Howard Wieman: http://rnc.lbl.gov/~wieman/HitFinding2DXsq.htm
+  // This is the probability of getting a good hit using a Chi**2 search on a 2D Gaussian distribution function
+  Double_t sx, goodHit ;
+  sx = 2 * TMath::Pi() *  searchRadiusRPhi * searchRadiusZ * HitDensity(radius) ;
+  goodHit =  1./(1+sx) ;
+  return ( goodHit ) ;  
+}
+
+Double_t KMCDetector::ProbGoodChiSqPlusConfHit ( Double_t radius, Double_t leff, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) 
+{
+  // Based on work by Ruben Shahoyen 
+  // This is the probability of getting a good hit using a Chi**2 search on a 2D Gaussian distribution function
+  // Plus, in addition, taking a "confidence level" and the "layer efficiency" into account 
+  // Following is correct for 2 DOF
+
+  Double_t c = -2 *TMath::Log(fConfLevel); // quantile at cut of confidence level
+  Double_t alpha = (1 + 2 * TMath::Pi() * HitDensity(radius) * searchRadiusRPhi * searchRadiusZ)/2; 
+  Double_t goodHit = leff/(2*alpha) * (1 - TMath::Exp(-alpha*c));
+  return ( goodHit ) ;  
+}
+
+Double_t KMCDetector::ProbNullChiSqPlusConfHit ( Double_t radius, Double_t leff, Double_t searchRadiusRPhi, Double_t searchRadiusZ ) 
+{
+  // Based on work by Ruben Shahoyen 
+  // This is the probability to not have any match to the track (see also :ProbGoodChiSqPlusConfHit:)
+
+  Double_t c = -2 *TMath::Log(fConfLevel); // quantile at cut of confidence level
+  Double_t alpha = (1 + 2 * TMath::Pi() * HitDensity(radius) * searchRadiusRPhi * searchRadiusZ)/2; 
+  Double_t nullHit = (1-leff+fConfLevel*leff)*TMath::Exp(-c*(alpha-1./2));
+  return ( nullHit ) ;  
+}
+
+Double_t KMCDetector::HitDensity ( Double_t radius ) 
+{
+  // Background (0-1) is included via 'OtherBackground' which multiplies the minBias rate by a scale factor.
+  // UPC electrons is a temporary kludge that is based on Kai Schweda's summary of Kai Hainken's MC results
+  // See K. Hencken et al. PRC 69, 054902 (2004) and PPT slides by Kai Schweda.
+  // Note that this function assumes we are working in CM and CM**2 [not meters].
+  // Based on work by Yan Lu 12/20/2006, all radii and densities in centimeters or cm**2.
+
+  //  Double_t MaxRadiusSlowDet = 0.1; //?   // Maximum radius for slow detectors.  Fast detectors 
+                                        // and only fast detectors reside outside this radius.
+  Double_t arealDensity = 0 ;
+  if (radius<0.01) return 0;
+
+  if ( radius >= fMaxRadiusSlowDet ) 
+    {
+      arealDensity  = OneEventHitDensity(fdNdEtaCent,radius)  ; // Fast detectors see central collision density (only)
+      arealDensity += OtherBackground*OneEventHitDensity(dNdEtaMinB,radius)  ;  // Increase density due to background 
+    }
+
+  if (radius < fMaxRadiusSlowDet )
+    { // Note that IntegratedHitDensity will always be minB one event, or more, even if integration time => zero.
+      arealDensity  = OneEventHitDensity(fdNdEtaCent,radius) 
+                   + IntegratedHitDensity(dNdEtaMinB,radius) 
+                   + UpcHitDensity(radius) ;
+      arealDensity += OtherBackground*IntegratedHitDensity(dNdEtaMinB,radius) ;  
+      // Increase density due to background 
+    } 
+
+  return ( arealDensity ) ;  
+}
+
+
+double KMCDetector::OneEventHitDensity( Double_t multiplicity, Double_t radius ) const
+{
+  // This is for one event at the vertex.  No smearing.
+  double den   = multiplicity / (2.*TMath::Pi()*radius*radius) * fDensFactorEta ; // 2 eta ?
+  // note: surface of sphere is  '4*pi*r^2'
+  //       surface of cylinder is '2*pi*r* h' 
+  return den ;
+} 
+
+
+double KMCDetector::IntegratedHitDensity(Double_t multiplicity, Double_t radius)
+{ 
+  // The integral of minBias events smeared over a gaussian vertex distribution.
+  // Based on work by Yan Lu 12/20/2006, all radii in centimeters.
+
+  Double_t zdcHz = Luminosity * 1.e-24 * CrossSectionMinB ;
+  Double_t den   = zdcHz * fIntegrationTime/1000. * multiplicity * Dist(0., radius) / (2.*TMath::Pi()*radius) ;
+
+  // Note that we do not allow the rate*time calculation to fall below one minB event at the vertex.
+  double dens1 = OneEventHitDensity(multiplicity,radius);
+  if ( den < dens1 )  den = dens1;
+
+  return den ;
+} 
+
+
+double KMCDetector::UpcHitDensity(Double_t radius)
+{ 
+  // QED electrons ...
+
+  Double_t mUPCelectrons ;                                 ;  
+  //  mUPCelectrons =  fLhcUPCscale * (1.23 - radius/6.5)      ;  // Fit to Kai Schweda summary tables at RHIC * 'scale' for LHC
+  mUPCelectrons = fLhcUPCscale*5456/(radius*radius)/dNdEtaMinB;      // Fit to 'Rossegger,Sadovsky'-Alice simulation
+  if ( mUPCelectrons < 0 ) mUPCelectrons =  0.0             ;  // UPC electrons fall off quickly and don't go to large R
+  mUPCelectrons *= IntegratedHitDensity(dNdEtaMinB,radius) ;  // UPCs increase Mulitiplicty ~ proportional to MinBias rate
+  mUPCelectrons *= UPCBackgroundMultiplier                 ;  // Allow for an external multiplier (eg 0-1) to turn off UPC
+
+  return mUPCelectrons ;
+} 
+
+
+double KMCDetector::Dist(double z, double r)
+{
+  // Convolute dEta/dZ  distribution with assumed Gaussian of vertex z distribution
+  // Based on work by Howard Wieman http://rnc.lbl.gov/~wieman/HitDensityMeasuredLuminosity7.htm
+  // Based on work by Yan Lu 12/20/2006, all radii and Z location in centimeters.
+  Int_t    index  =  1     ;     // Start weight at 1 for Simpsons rule integration
+  Int_t    nsteps =  301   ;     // NSteps must be odd for Simpson's rule to work
+  double   dist   =  0.0   ;
+  double   dz0    =  ( 4*SigmaD - (-4)*SigmaD ) / (nsteps-1)  ;  //cm
+  double    z0    =  0.0   ;     //cm
+  for(int i=0; i<nsteps; i++){
+    if ( i == nsteps-1 ) index = 1 ;
+    z0 = -4*SigmaD + i*dz0 ;
+    dist += index * (dz0/3.) * (1/sqrt(2.*TMath::Pi())/SigmaD) * exp(-z0*z0/2./SigmaD/SigmaD) * 
+      (1/sqrt((z-z0)*(z-z0) + r*r)) ;
+    if ( index != 4 ) index = 4; else index = 2 ;
+  }
+  return dist; 
+}
+
+#define  PZero   0.861  // Momentum of back to back decay particles in the CM frame
+#define  EPiZero 0.872  // Energy of the pion from a D0 decay at rest
+#define  EKZero  0.993  // Energy of the Kaon from a D0 decay at rest
+
+Double_t KMCDetector::D0IntegratedEfficiency( Double_t pt, Double_t corrEfficiency[][20] ) const {
+  // Math from Ron Longacre.  Note hardwired energy to bin conversion for PtK and PtPi.
+
+  Double_t const1  =  pt / D0Mass ;
+  Double_t const2  =  TMath::Sqrt(pt*pt+D0Mass*D0Mass) / D0Mass ;
+  Double_t sum, ptPi, ptK ;
+  Double_t effp, effk ;
+
+  sum = 0.0 ;
+  for ( Int_t k = 0 ; k < 360 ; k++ )   {
+    
+    Double_t theta = k * TMath::Pi() / 180. ;
+    
+    ptPi = TMath::Sqrt( 
+                      PZero*PZero*TMath::Cos(theta)*TMath::Cos(theta)*const2*const2 +
+                      const1*const1*EPiZero*EPiZero -
+                      2*PZero*TMath::Cos(theta)*const2*const1*EPiZero +
+                      PZero*PZero*TMath::Sin(theta)*TMath::Sin(theta)
+                      ) ;
+    
+    ptK = TMath::Sqrt( 
+                     PZero*PZero*TMath::Cos(theta)*TMath::Cos(theta)*const2*const2 +
+                     const1*const1*EKZero*EKZero +
+                     2*PZero*TMath::Cos(theta)*const2*const1*EKZero +
+                     PZero*PZero*TMath::Sin(theta)*TMath::Sin(theta)
+                     ) ;
+
+    // JT Test Remove 100 MeV/c in pt to simulate eta!=0 decays
+    Int_t pionindex = (int)((ptPi-0.1)*100.0 - 65.0*TMath::Abs(fBFieldG)) ; 
+    Int_t kaonindex = (int)((ptK -0.1)*100.0 - 65.0*TMath::Abs(fBFieldG)) ; 
+      
+    if ( pionindex >= 20 ) pionindex = 399 ;
+    if ( pionindex >= 0 )   effp = corrEfficiency[0][pionindex] ;
+    if ( pionindex <  0 )   effp = (corrEfficiency[0][1]-corrEfficiency[0][0])*pionindex + corrEfficiency[0][0] ; // Extrapolate if reqd
+    if ( effp < 0 )         effp = 0 ;
+
+    if ( kaonindex >= 20 ) kaonindex = 399 ;
+    if ( kaonindex >= 0 )   effk = corrEfficiency[1][kaonindex] ;
+    if ( kaonindex <  0 )   effk = (corrEfficiency[1][1]-corrEfficiency[1][0])*kaonindex + corrEfficiency[1][0] ; // Extrapolate if reqd
+    if ( effk < 0 )         effk = 0 ;
+
+    // Note that we assume that the Kaon Decay efficiency has already been inlcuded in the kaon efficiency used here.
+      
+    sum += effp * effk ;
+  }    
+  
+  Double_t mean =sum/360; 
+  return mean ;
+  
+}
+
+KMCProbe* KMCDetector::PrepareKalmanTrack(double pt, double lambda, double mass, int charge, double phi, double x,double y, double z)
+{
+  // Prepare trackable Kalman track at the farthest position
+  //
+  // Set track parameters
+  // Assume track started at (0,0,0) and shoots out on the X axis, and B field is on the Z axis
+  fProbe.Reset();
+  fProbe.SetMass(mass);
+  KMCProbe* probe = new KMCProbe(fProbe);
+  double *trPars = (double*)probe->GetParameter();
+  double *trCov  = (double*)probe->GetCovariance();
+  double xyz[3] = {x,y,z};
+  probe->Global2LocalPosition(xyz,phi);
+  probe->Set(xyz[0],phi,trPars,trCov);
+  trPars[KMCProbe::kY] = xyz[1];
+  trPars[KMCProbe::kZ] = xyz[2];
+  trPars[KMCProbe::kSnp] = 0;                       //            track along X axis at the vertex
+  trPars[KMCProbe::kTgl] = TMath::Tan(lambda);                // dip
+  trPars[KMCProbe::kPtI] = charge/pt;               //            q/pt      
+  //
+  // put tiny errors to propagate to the outer-most radius
+  trCov[KMCProbe::kY2] = trCov[KMCProbe::kZ2] = trCov[KMCProbe::kSnp2] = trCov[KMCProbe::kTgl2] = trCov[KMCProbe::kPtI2] = 1e-20;
+  fProbe = *probe;  // store original track
+  //
+  // propagate to last layer
+  fLastActiveLayerTracked = 0;
+  for (Int_t j=0; j<=fLastActiveLayer; j++) {
+    KMCLayer* lr = GetLayer(j);
+    lr->Reset();
+    //
+    if (!PropagateToLayer(probe,lr,1)) break;
+    if (!probe->CorrectForMeanMaterial(lr, kFALSE)) break;
+    //
+    lr->fClCorr.Set(probe->GetY(),probe->GetZ(), probe->GetX(), probe->GetAlpha());
+    if (!lr->IsDead()) fLastActiveLayerTracked = j;
+  }
+  probe->ResetCovMat();// reset cov.matrix
+  printf("Last active layer trracked: %d (out of %d)\n",fLastActiveLayerTracked,fLastActiveLayer);
+  //
+  return probe;
+}
+
+
+
+TGraph * KMCDetector::GetGraphMomentumResolution(Int_t color, Int_t linewidth) {
+  //
+  // returns the momentum resolution 
+  //
+  
+  TGraph *graph = new TGraph(20, fTransMomenta, fMomentumRes);
+  graph->SetTitle("Momentum Resolution .vs. Pt" ) ;
+  //  graph->GetXaxis()->SetRangeUser(0.,5.0) ;
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->SetTitle("Momentum Resolution (%)") ;
+  graph->GetYaxis()->CenterTitle();
+
+  graph->SetMaximum(20) ;
+  graph->SetMinimum(0.1) ;
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  graph->SetLineWidth(linewidth);
+
+  return graph;
+
+}
+
+TGraph * KMCDetector::GetGraphPointingResolution(Int_t axis, Int_t color, Int_t linewidth) {
+  // Returns the pointing resolution
+  // axis = 0 ... rphi pointing resolution
+  // axis = 1 ... z pointing resolution
+  //
+
+  TGraph * graph =  0;
+
+  if (axis==0) {
+    graph = new TGraph ( 20, fTransMomenta, fResolutionRPhi ) ;
+    graph->SetTitle("R-#phi Pointing Resolution .vs. Pt" ) ;
+    graph->GetYaxis()->SetTitle("R-#phi Pointing Resolution (#mum)") ;
+  } else {
+    graph =  new TGraph ( 20, fTransMomenta, fResolutionZ ) ;
+    graph->SetTitle("Z Pointing Resolution .vs. Pt" ) ;
+    graph->GetYaxis()->SetTitle("Z Pointing Resolution (#mum)") ;
+  }
+  
+  graph->SetMinimum(1) ;
+  graph->SetMaximum(300.1) ;
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->CenterTitle();
+  
+  graph->SetLineWidth(linewidth);
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  
+  return graph;
+
+}
+
+
+TGraph * KMCDetector::GetGraphPointingResolutionTeleEqu(Int_t axis,Int_t color, Int_t linewidth) {
+  //
+  // returns the Pointing resolution (accoring to Telescope equation)
+  // axis =0 ... in rphi
+  // axis =1 ... in z
+  //
+  
+  Double_t resolution[20];
+
+  Double_t layerResolution[2];
+  Double_t layerRadius[2];
+  Double_t layerThickness[2];
+
+  Int_t count =0; // search two first active layers
+  printf("Telescope equation for layers:  ");
+  for (Int_t i = 0; i<fLayers.GetEntries(); i++) {
+    KMCLayer *l = (KMCLayer*)fLayers.At(i);
+    if (!l->IsDead() && l->fR>0) {
+      layerRadius[count]     = l->fR;
+      layerThickness[count]  = l->fx2X0;
+      if (axis==0) {
+       layerResolution[count] = l->fPhiRes;
+      } else {
+       layerResolution[count] = l->fZRes;
+      }
+      printf("%s, ",l->GetName());
+      count++;
+    }
+    if (count>=2) break;       
+  }
+  printf("\n");
+
+  Double_t pt, momentum, thickness,aMCS ;
+  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); 
+
+  for ( Int_t i = 0 ; i < 20 ; i++ ) { 
+    // Reference data as if first two layers were acting all alone 
+    pt  =  fTransMomenta[i]  ;
+    momentum = pt / TMath::Cos(lambda)   ;  // Total momentum
+    resolution[i] =  layerResolution[0]*layerResolution[0]*layerRadius[1]*layerRadius[1] 
+      +  layerResolution[1]*layerResolution[1]*layerRadius[0]*layerRadius[0] ;
+    resolution[i] /= ( layerRadius[1] - layerRadius[0] ) * ( layerRadius[1] - layerRadius[0] ) ;
+    thickness = layerThickness[0] / TMath::Sin(TMath::Pi()/2 - lambda) ;
+    aMCS = ThetaMCS(fParticleMass, thickness, momentum) ;
+    resolution[i] += layerRadius[0]*layerRadius[0]*aMCS*aMCS ;
+    resolution[i] =  TMath::Sqrt(resolution[i]) * 10000.0 ;  // result in microns
+  }
+
+
+
+  TGraph* graph = new TGraph ( 20, fTransMomenta, resolution ) ;
+   
+  if (axis==0) {
+    graph->SetTitle("RPhi Pointing Resolution .vs. Pt" ) ;
+    graph->GetYaxis()->SetTitle("RPhi Pointing Resolution (#mum) ") ;
+  } else {
+    graph->SetTitle("Z Pointing Resolution .vs. Pt" ) ;
+    graph->GetYaxis()->SetTitle("Z Pointing Resolution (#mum) ") ;
+  }
+  graph->SetMinimum(1) ;
+  graph->SetMaximum(300.1) ;
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->CenterTitle();
+  
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  graph->SetLineStyle(kDashed);
+  graph->SetLineWidth(linewidth);
+
+  return graph;
+
+}
+
+TGraph * KMCDetector::GetGraphRecoEfficiency(Int_t particle,Int_t color, Int_t linewidth) {
+  //
+  // particle = 0 ... choosen particle (setted particleMass)
+  // particle = 1 ... Pion
+  // particle = 2 ... Kaon
+  // particle = 3 ... D0
+  //
+  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); 
+  
+  Double_t particleEfficiency[20]; // with chosen particle mass
+  Double_t kaonEfficiency[20], pionEfficiency[20], d0efficiency[20]; 
+  Double_t partEfficiency[2][20];
+  
+  if (particle != 0) {
+    // resulting Pion and Kaon efficiency scaled with overall efficiency
+    Double_t doNotDecayFactor;
+    for ( Int_t massloop = 0 ; massloop < 2 ; massloop++) { //0-pion, 1-kaon
+      
+      for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+       // JT Test Let the kaon decay.  If it decays inside the TPC ... then it is gone; for all decays < 130 cm.
+       Double_t momentum = fTransMomenta[j] / TMath::Cos(lambda)           ;  // Total momentum at average rapidity
+       if ( massloop == 1 ) { // KAON
+         doNotDecayFactor  = TMath::Exp(-130/(371*momentum/KaonMass)) ;  // Decay length for kaon is 371 cm.
+         kaonEfficiency[j] = fEfficiency[1][j] * AcceptanceOfTpcAndSi*doNotDecayFactor ;
+       } else { // PION
+         doNotDecayFactor = 1.0 ;
+         pionEfficiency[j] = fEfficiency[0][j] * AcceptanceOfTpcAndSi*doNotDecayFactor ;       
+       }
+       partEfficiency[0][j] = pionEfficiency[j];
+       partEfficiency[1][j] = kaonEfficiency[j];
+      }      
+    }
+    
+    // resulting estimate of the D0 efficiency
+    for ( Int_t j = 0 ; j < 20 ; j++ ) {
+      d0efficiency[j] = D0IntegratedEfficiency(fTransMomenta[j],partEfficiency);
+    }
+  } else { 
+    for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+      particleEfficiency[j] = fEfficiency[2][j]* AcceptanceOfTpcAndSi;
+      // NOTE: Decay factor (see kaon) should be included to be realiable
+    }
+  }
+
+  for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+    pionEfficiency[j]     *= 100;
+    kaonEfficiency[j]     *= 100;
+    d0efficiency[j]       *= 100;
+    particleEfficiency[j] *= 100;
+  }
+  TGraph * graph =  0;
+  if (particle==0) {
+    graph = new TGraph ( 20, fTransMomenta, particleEfficiency ) ; // choosen mass
+    graph->SetLineWidth(1);
+  }  else if (particle==1) {
+    graph = new TGraph ( 20, fTransMomenta, pionEfficiency ) ;
+    graph->SetLineWidth(1);
+  }  else if (particle ==2) {
+    graph = new TGraph ( 20, fTransMomenta, kaonEfficiency ) ;
+    graph->SetLineWidth(1);
+  }  else if (particle ==3) {
+    graph = new TGraph ( 20, fTransMomenta, d0efficiency ) ;
+    graph->SetLineStyle(kDashed);
+  } else 
+    return 0;
+
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->SetTitle("Efficiency (%)") ;
+  graph->GetYaxis()->CenterTitle();
+         
+  graph->SetMinimum(0.01) ; 
+  graph->SetMaximum(100)  ; 
+
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  graph->SetLineWidth(linewidth);
+
+  return graph;
+}
+
+TGraph * KMCDetector::GetGraphRecoFakes(Int_t particle,Int_t color, Int_t linewidth) {
+  //
+  // particle = 0 ... choosen particle (setted particleMass)
+  // particle = 1 ... Pion
+  // particle = 2 ... Kaon
+  //
+
+  Double_t lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-1*fAvgRapidity)); 
+  
+  Double_t particleFake[20]; // with chosen particle mass
+  Double_t kaonFake[20], pionFake[20];
+  Double_t partFake[2][20];
+  
+  if (particle != 0) {
+    // resulting Pion and Kaon efficiency scaled with overall efficiency
+    Double_t doNotDecayFactor;
+    for ( Int_t massloop = 0 ; massloop < 2 ; massloop++) { //0-pion, 1-kaon
+      
+      for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+       // JT Test Let the kaon decay.  If it decays inside the TPC ... then it is gone; for all decays < 130 cm.
+       Double_t momentum = fTransMomenta[j] / TMath::Cos(lambda)           ;  // Total momentum at average rapidity
+       if ( massloop == 1 ) { // KAON
+         doNotDecayFactor  = TMath::Exp(-130/(371*momentum/KaonMass)) ;  // Decay length for kaon is 371 cm.
+         kaonFake[j] = fFake[1][j] /( doNotDecayFactor) ;
+       } else { // PION
+         pionFake[j] = fFake[0][j] ;   
+       }
+       partFake[0][j] = pionFake[j];
+       partFake[1][j] = kaonFake[j];
+      }      
+    }
+    
+  } else { 
+    for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+      particleFake[j] = fFake[2][j];
+      // NOTE: Decay factor (see kaon) should be included to be realiable
+    }
+  }
+
+  for ( Int_t j = 0 ; j < 20 ; j++ ) { 
+    pionFake[j]     *= 100;
+    kaonFake[j]     *= 100;
+    particleFake[j] *= 100;
+  }
+  TGraph * graph =  0;
+  if (particle==0) {
+    graph = new TGraph ( 20, fTransMomenta, particleFake ) ; // choosen mass
+    graph->SetLineWidth(1);
+  }  else if (particle==1) {
+    graph = new TGraph ( 20, fTransMomenta, pionFake ) ;
+    graph->SetLineWidth(1);
+  }  else if (particle ==2) {
+    graph = new TGraph ( 20, fTransMomenta, kaonFake ) ;
+    graph->SetLineWidth(1);
+  } 
+  
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->SetTitle("Fake (%)") ;
+  graph->GetYaxis()->CenterTitle();
+         
+  graph->SetMinimum(0.01) ; 
+  graph->SetMaximum(100)  ; 
+
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  graph->SetLineWidth(linewidth);
+
+  return graph;
+}
+
+
+TGraph* KMCDetector::GetGraphImpactParam(Int_t mode, Int_t axis, Int_t color, Int_t linewidth) {
+  //
+  // returns the Impact Parameter d0 (convolution of pointing resolution and vtx resolution)
+  // mode 0: impact parameter (convolution of pointing and vertex resolution)
+  // mode 1: pointing resolution
+  // mode 2: vtx resolution 
+  
+  
+  TGraph *graph = new TGraph();
+
+  //  TFormula vtxResRPhi("vtxRes","50-2*x"); // 50 microns at pt=0, 15 microns at pt =20 ?
+  TFormula vtxResRPhi("vtxRes","35/(x+1)+10"); // 
+  TFormula vtxResZ("vtxResZ","600/(x+6)+10"); // 
+    
+  TGraph *trackRes = GetGraphPointingResolution(axis,1);
+  Double_t *pt = trackRes->GetX();
+  Double_t *trRes = trackRes->GetY();
+  for (Int_t ip =0; ip<trackRes->GetN(); ip++) {
+    Double_t vtxRes = 0;
+    if (axis==0) 
+      vtxRes = vtxResRPhi.Eval(pt[ip]);
+    else 
+      vtxRes = vtxResZ.Eval(pt[ip]);
+    
+    if (mode==0)
+      graph->SetPoint(ip,pt[ip],TMath::Sqrt(vtxRes*vtxRes+trRes[ip]*trRes[ip]));
+    else if (mode ==1)
+      graph->SetPoint(ip,pt[ip],trRes[ip]);
+    else
+      graph->SetPoint(ip,pt[ip],vtxRes);
+  }
+  
+  graph->SetTitle("d_{0} r#phi resolution .vs. Pt" ) ;
+  graph->GetYaxis()->SetTitle("d_{0} r#phi resolution (#mum)") ;
+  
+  graph->SetMinimum(1) ;
+  graph->SetMaximum(300.1) ;
+  graph->GetXaxis()->SetTitle("Transverse Momentum (GeV/c)") ;
+  graph->GetXaxis()->CenterTitle();
+  graph->GetXaxis()->SetNoExponent(1) ;
+  graph->GetXaxis()->SetMoreLogLabels(1) ;
+  graph->GetYaxis()->CenterTitle();
+  
+  graph->SetLineColor(color);
+  graph->SetMarkerColor(color);
+  graph->SetLineWidth(linewidth);
+
+  return graph;
+
+}
+
+TGraph* KMCDetector::GetGraph(Int_t number, Int_t color, Int_t linewidth) {
+  // 
+  // returns graph according to the number
+  //
+  switch(number) {
+  case 1:
+    return GetGraphPointingResolution(0,color, linewidth); // dr
+  case 2:
+    return GetGraphPointingResolution(1,color, linewidth); // dz
+  case 3:
+    return GetGraphPointingResolutionTeleEqu(0,color, linewidth); // dr - tele
+  case 4:
+    return GetGraphPointingResolutionTeleEqu(1,color, linewidth); // dz - tele
+  case 5:
+    return GetGraphMomentumResolution(color, linewidth); // pt resolution
+  case 10:
+    return GetGraphRecoEfficiency(0, color, linewidth);  // tracked particle
+  case 11:
+    return GetGraphRecoEfficiency(1, color, linewidth);  // eff. pion
+  case 12:
+    return GetGraphRecoEfficiency(2, color, linewidth);  // eff. kaon
+  case 13: 
+    return GetGraphRecoEfficiency(3, color, linewidth);  // eff. D0
+  case 15:
+    return GetGraphRecoFakes(0, color, linewidth);  // Fake tracked particle
+  case 16:
+    return GetGraphRecoFakes(1, color, linewidth);  // Fake pion
+  case 17:
+    return GetGraphRecoFakes(2, color, linewidth);  // Fake kaon
+  default:
+    printf(" Error: chosen graph number not valid\n");
+  }
+  return 0;
+
+}
+
+void KMCDetector::MakeAliceAllNew(Bool_t flagTPC,Bool_t flagMon, int setVer) {
+  
+  // All New configuration with X0 = 0.3 and resolution = 4 microns
+  
+  AddLayer((char*)"bpipe_its",2.0,0.0022, 0.092); // beam pipe, 0.5 mm Be
+  AddLayer((char*)"vertex_its",     0,     0); // dummy vertex for matrix calculation
+  if (fgVtxConstraint[0]>0 && fgVtxConstraint[1]>0) {
+    printf("vertex will work as constraint: %.4f %.4f\n",fgVtxConstraint[0],fgVtxConstraint[1]);
+    SetResolution((char*)"vertex_its",fgVtxConstraint[0],fgVtxConstraint[1]);
+  }
+  //
+  // new ideal Pixel properties?
+  Double_t x0     = 0.0050;
+  Double_t resRPhi = 0.0006;
+  Double_t resZ   = 0.0006;
+  Double_t xrho = 0.0116;  // assume 0.5mm of silicon for eloss
+  //
+  if (flagMon) {
+    x0 *= 3./5.;
+    xrho *=3./5.;
+    resRPhi = 0.0004;
+    resZ   = 0.0004;
+  }
+
+  double sclD = 1;
+  double sclZ = 1;
+
+  // default all new  
+  if (setVer<=0) {
+    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); 
+  }
+  else if (setVer==1) {
+    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its2",  2.8 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its3",  3.6 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its4", 20.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its5", 22.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its6", 43.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its7", 43.6 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    //
+    /*
+    UInt_t patt[] = {
+      KMCTrackSummary::Bits(1,1,1),
+      KMCTrackSummary::Bits(0,0,0,1,1),
+      KMCTrackSummary::Bits(0,0,0,0,0,1,1)
+    };
+    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));
+    */
+  }
+  else if (setVer==2) {
+    AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its1a", 2.8 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its2",  3.6 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its2a", 4.2 ,  x0, xrho, resRPhi, resZ); 
+    AddLayer((char*)"its3", 20.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its4", 22.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its5", 33.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its6", 43.0 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    AddLayer((char*)"its7", 43.6 ,  x0, xrho, resRPhi*sclD, resZ*sclZ); 
+    //
+    /*
+    UInt_t patt[] = {
+      KMCTrackSummary::Bits(1,1,1,1),
+      KMCTrackSummary::Bits(0,0,0,0,1,1),
+      KMCTrackSummary::Bits(0,0,0,0,0,0,1,1,1)
+    };
+    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));
+    */
+  }
+   /*
+  // last 2 layers strips
+  double resRPStr=0.0020, resZStr = 0.0830;
+  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPStr, resZStr); 
+  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPStr, resZStr); 
+   */
+  //*/
+  /*
+  // resolution scaled with R as res(2.2) * R/2.2
+  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); 
+  KMCLayer* lr0 = 0;
+  for (int i=0;i<GetNActiveITSLayers();i++) {
+    KMCLayer *lr = GetActiveLayer(i);
+    if (lr->IsVertex()) continue;
+    if (lr0==0) {
+      lr0=lr; 
+      //  continue;
+    }
+    double scl = 5*lr->GetRadius()/lr0->GetRadius();
+    SetResolution((char*)lr->GetName(), resRPhi*scl, resZ*scl*4);
+  }
+  */
+  /*
+  // 1st 2 layers double
+  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its1a",  2.8 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its2a",  4.2 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its3a",  6.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); 
+  */
+  /*
+  // last 4 layers doubled
+  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its4a", 12.8 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its5", 23.5 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its5a", 23.9 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its6", 39.6 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its6a", 40.0 ,  x0, xrho, resRPhi, resZ); 
+
+  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its7a", 43.4 ,  x0, xrho, resRPhi, resZ); 
+  */
+
+  /* //last 3 lr together 
+  AddLayer((char*)"its1",  2.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its2",  3.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its3",  6.8 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its4", 12.4 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its5", 42.2 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its6", 42.6 ,  x0, xrho, resRPhi, resZ); 
+  AddLayer((char*)"its7", 43.0 ,  x0, xrho, resRPhi, resZ); 
+  */
+  if (flagTPC) {
+    AddTPC(0.1,0.1);                        // TPC
+  }
+  PrintLayout();
+}
+
+void KMCDetector::MakeAliceCurrent(Bool_t flagTPC, Int_t AlignResiduals) {
+
+  // Numbers taken from 
+  // 2010 JINST 5 P03003 - Alignment of the ALICE Inner Tracking System with cosmic-ray tracks
+  // number for misalingment: private communication with Andrea Dainese
+
+  //  1.48e-01, 2.48e-01,2.57e-01, 1.34e-01, 3.34e-01,3.50e-01, 2.22e-01, 2.38e-01,2.25e-01};
+
+  AddLayer((char*)"vertex_its",     0,     0); // dummy vertex for matrix calculation
+  if (fgVtxConstraint[0]>0 && fgVtxConstraint[1]>0) {
+    printf("vertex will work as constraint: %.4f %.4f",fgVtxConstraint[0],fgVtxConstraint[1]);
+    SetResolution((char*)"vertex_its",fgVtxConstraint[0],fgVtxConstraint[1]);
+  }
+  //
+  AddLayer((char*)"bpipe_its",2.94,0.0022, 1.48e-01); // beam pipe
+  AddLayer((char*)"tshld1_its",11.5,0.0065, 1.34e-01); // Thermal shield  // 1.3% /2
+  AddLayer((char*)"tshld2_its",31.0,0.0108, 2.22e-01); // Thermal shield  // 1.3% /2
+  //
+  if (flagTPC) {
+    AddTPC(0.1,0.1);                        // TPC
+  }
+  // Adding the ITS - current configuration
+  
+  if (AlignResiduals==0) {
+    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, 0.0012, 0.0130);
+    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, 0.0012, 0.0130);
+    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, 0.0035, 0.0025);
+    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, 0.0035, 0.0025);
+    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, 0.0020, 0.0830);
+    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, 0.0020, 0.0830);
+    /*
+    UInt_t patt[] = {
+      KMCTrackSummary::Bits(1,1),
+      KMCTrackSummary::Bits(0,0,1,1),
+      KMCTrackSummary::Bits(0,0,0,0,1,1)
+    };
+    RequirePattern( patt, sizeof(patt)/sizeof(UInt_t));
+    */
+  } else if (AlignResiduals==1) {
+
+    // tracking errors ...
+    // (Additional systematic errors due to misalignments) ... 
+    // itsRecoParam->SetClusterMisalErrorYBOn(0.0010,0.0030,0.0500,0.0500,0.0020,0.0020);  // [cm]
+    // itsRecoParam->SetClusterMisalErrorZBOn(0.0050,0.0050,0.0050,0.0050,0.1000,0.1000);
+
+    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0010*0.0010), 
+            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));
+    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0030*0.0030),
+            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));
+    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0100*0.0100),
+            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));
+    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0100*0.0100),
+            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));
+    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020), 
+            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));
+    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020),
+            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));   
+    
+  } else if (AlignResiduals==2) {
+
+    
+    // tracking errors ... PLUS ... module misalignment
+    
+    // itsRecoParam->SetClusterMisalErrorYBOn(0.0010,0.0030,0.0500,0.0500,0.0020,0.0020);  // [cm]
+    // itsRecoParam->SetClusterMisalErrorZBOn(0.0050,0.0050,0.0050,0.0050,0.1000,0.1000);
+    
+    //  the ITS modules are misalignment with small gaussian smearings with
+    //  sigmarphi ~ 8, 10, 10 micron in SPD, SDD, SSD
+    
+    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0010*0.0010+0.0008*0.0008), 
+            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));
+    AddLayer((char*)"spd2_ots", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0030*0.0030+0.0008*0.0008),
+            TMath::Sqrt(0.0130*0.0130+0.0050*0.0050));
+    AddLayer((char*)"sdd1_ots",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0500*0.0500+0.0010*0.0010),
+            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));
+    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0500*0.0500+0.0010*0.0010),
+            TMath::Sqrt(0.0025*0.0025+0.0050*0.0050));
+    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020+0.0010*0.0010), 
+            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000));
+    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0020*0.0020+0.0010*0.0010),
+            TMath::Sqrt(0.0830*0.0830+0.1000*0.1000)); 
+
+  } else {
+      
+      //  the ITS modules are misalignment with small gaussian smearings with
+      //  sigmarphi ~ 8, 10, 10 micron in SPD, SDD, SSD
+      //  unknown in Z ????
+
+    AddLayer((char*)"spd1_its", 3.9, 0.0114, 2.48e-01, TMath::Sqrt(0.0012*0.0012+0.0008*0.0008), 
+            TMath::Sqrt(0.0130*0.0130+0.000*0.000));
+    AddLayer((char*)"spd2_its", 7.6, 0.0114, 2.57e-01, TMath::Sqrt(0.0012*0.0012+0.0008*0.0008),
+            TMath::Sqrt(0.0130*0.0130+0.000*0.000));
+    AddLayer((char*)"sdd1_its",15.0, 0.0113, 3.34e-01, TMath::Sqrt(0.0035*0.0035+0.0010*0.0010),
+            TMath::Sqrt(0.0025*0.0025+0.000*0.000));
+    AddLayer((char*)"sdd2_its",23.9, 0.0126, 3.50e-01, TMath::Sqrt(0.0035*0.0035+0.0010*0.0010),
+            TMath::Sqrt(0.0025*0.0025+0.000*0.000));
+    AddLayer((char*)"ssd1_its",38.0, 0.0083, 2.38e-01, TMath::Sqrt(0.0020*0.0020+0.0010*0.0010), 
+            TMath::Sqrt(0.0830*0.0830+0.000*0.000));
+    AddLayer((char*)"ssd2_its",43.0, 0.0086, 2.25e-01, TMath::Sqrt(0.0020*0.0020+0.0010*0.0010),
+            TMath::Sqrt(0.0830*0.0830+0.000*0.000));       
+  }
+  
+}
+
+
+void KMCDetector::MakeStandardPlots(Bool_t add, Int_t color, Int_t linewidth,Bool_t onlyPionEff) {
+  //
+  // Produces the standard performace plots
+  //
+  if (!add) {
+
+    TCanvas *c1 = new TCanvas("c1","c1");//,100,100,500,500);  
+    c1->Divide(2,2);
+    
+    c1->cd(1);  gPad->SetGridx();   gPad->SetGridy(); 
+    gPad->SetLogx(); 
+    TGraph *eff = GetGraphRecoEfficiency(1,color,linewidth);
+    eff->SetTitle("Efficiencies");
+    eff->Draw("AL");
+    if (!onlyPionEff) {
+      GetGraphRecoEfficiency(2,color,linewidth)->Draw("L");
+      GetGraphRecoEfficiency(3,color,linewidth)->Draw("L");
+    }
+    c1->cd(2); gPad->SetGridx();   gPad->SetGridy(); 
+    gPad->SetLogy();  gPad->SetLogx(); 
+    GetGraphMomentumResolution(color,linewidth)->Draw("AL");
+    
+    c1->cd(3); gPad->SetGridx();   gPad->SetGridy(); 
+    gPad->SetLogx(); 
+    GetGraphPointingResolution(0,color,linewidth)->Draw("AL");
+    
+    c1->cd(4); gPad->SetGridx();   gPad->SetGridy(); 
+    gPad->SetLogx(); 
+    GetGraphPointingResolution(1,color,linewidth)->Draw("AL");
+
+  } else {
+
+    TVirtualPad *c1 = gPad->GetMother();
+
+    c1->cd(1);
+    GetGraphRecoEfficiency(1,color,linewidth)->Draw("L");
+    if (!onlyPionEff) {
+      GetGraphRecoEfficiency(2,color,linewidth)->Draw("L");
+      GetGraphRecoEfficiency(3,color,linewidth)->Draw("L");
+    }
+    c1->cd(2); GetGraphMomentumResolution(color,linewidth)->Draw("L");
+    
+    c1->cd(3); GetGraphPointingResolution(0,color,linewidth)->Draw("L");
+    
+    c1->cd(4); GetGraphPointingResolution(1,color,linewidth)->Draw("L");
+    
+  }
+
+}
+
+void KMCDetector::ApplyMS(KMCProbe* trc, double x2X0) const
+{
+  // simulate random modification of track params due to the MS
+  if (x2X0<=0) return;
+  double alpha = trc->GetAlpha(); // store original alpha
+  double mass = trc->GetMass();
+  //
+  double snp = trc->GetSnp();
+  double dip = trc->GetTgl();
+  Double_t angle=TMath::Sqrt((1.+ dip*dip)/((1-snp)*(1.+snp)));
+  x2X0 *= angle;
+  //
+  static double covCorr[15],covDum[21]={0};
+  static double mom[3],pos[3];
+  double *cov = (double*) trc->GetCovariance();
+  memcpy(covCorr,cov,15*sizeof(double));
+  trc->GetXYZ(pos);
+  trc->GetPxPyPz(mom);
+  double pt2 = mom[0]*mom[0]+mom[1]*mom[1];
+  double pt = TMath::Sqrt(pt2);
+  double ptot2 = pt2 + mom[2]*mom[2];
+  double ptot  = TMath::Sqrt(ptot2);
+  double beta = ptot/TMath::Sqrt(ptot2 + mass*mass);
+  double sigth = TMath::Sqrt(x2X0)*0.014/(ptot*beta);
+  //
+  // a la geant
+  double phiSC = gRandom->Rndm()*TMath::Pi();
+  double thtSC = gRandom->Gaus(0,1.4142*sigth);
+  //  printf("MS phi: %+.5f tht: %+.5f\n",phiSC,thtSC);
+  double sn = TMath::Sin(thtSC);
+  double dx = sn*TMath::Sin(phiSC);
+  double dy = sn*TMath::Cos(phiSC);  
+  double dz = TMath::Cos(thtSC);
+  double v[3];
+  //  printf("Before: %+.3e %+.3e %+.3e | MS: %+.3e %+.3e\n",mom[0],mom[1],mom[2],thtSC,phiSC);
+  for (int i=3;i--;) mom[i] /= ptot;
+  double vmm = TMath::Sqrt(mom[0]*mom[0]+mom[1]*mom[1]);
+  if (!IsZero(pt)) {
+    double pd1 = mom[0]/vmm;
+    double pd2 = mom[1]/vmm;
+    v[0] = pd1*mom[2]*dx - pd2*dy + mom[0]*dz;
+    v[1] = pd2*mom[2]*dx + pd1*dy + mom[1]*dz;
+    v[2] = -vmm*dx                + mom[2]*dz;
+  }
+  else {
+    v[0] = dx;
+    v[1] = dy;
+    v[2] = dz*TMath::Sign(1.,mom[2]);
+  }
+  double nrm = TMath::Sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
+  //  printf("before :%+e %+e %+e  || %+e %+e %+e %+e\n",mom[0],mom[1],mom[2],  sigth, x2X0, pt, beta);
+  //  trc->Print();
+  // direction cosines -> p
+  for (int i=3;i--;) mom[i] = ptot*v[i]/nrm;
+  //  printf("After : %+.3e %+.3e %+.3e\n",mom[0],mom[1],mom[2]);
+  trc->Set(pos,mom,covDum,trc->Charge());
+  //
+  trc->Rotate(alpha);
+  memcpy(cov,covCorr,15*sizeof(double));
+  //
+}
+
+//________________________________________________________________________________
+Bool_t KMCDetector::TransportKalmanTrackWithMS(KMCProbe *probTr, int maxLr) const
+{
+  // Transport track till layer maxLr, applying random MS
+  //
+  for (Int_t j=0; j<maxLr; j++) {
+    KMCLayer* lr0 = (KMCLayer*)fLayers.At(j);
+    KMCLayer* lr  = (KMCLayer*)fLayers.At(j+1);
+    if (!lr0->IsVertex()) {
+      ApplyMS(probTr,lr0->fx2X0); // apply MS
+      if (!probTr->CorrectForMeanMaterial(lr0,kFALSE)) return kFALSE; 
+    }
+    //
+    if (!PropagateToLayer(probTr,lr,1)) return kFALSE;
+    // store randomized cluster local coordinates and phi
+    lr->ResetBgClusters();
+    double rz,ry;
+    gRandom->Rannor(rz,ry);
+    lr->GetMCCluster()->Set(probTr->GetY()+ry*lr->GetPhiRes(),probTr->GetZ()+rz*lr->GetZRes(), 
+                              probTr->GetX(), probTr->GetAlpha() );    
+    //
+  }
+  //
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Bool_t KMCDetector::SolveSingleTrack(Double_t mass, Double_t pt, Double_t eta, TObjArray* sumArr,int nMC, int offset)
+{
+  // analityc and fullMC (nMC trials) evaluaion of tracks with given kinematics.
+  // the results are filled in KMCTrackSummary objects provided via summArr array
+  //
+  int progressP = 10;//0; // print progress in percents
+  //
+  progressP = int(nMC*0.01*progressP);
+
+  if (!SolveSingleTrackViaKalman(mass,pt,eta)) return kFALSE;
+  //
+  // Store non-updated track errors of inward propagated seed >>>>>>>>
+  int maxLr = fLastActiveITSLayer + offset;
+  if (maxLr >= fLastActiveLayerTracked-1) maxLr = fLastActiveLayerTracked;
+  KMCProbe probeTmp = fProbe; // original probe at vertex
+  KMCLayer* lr = 0;
+  for (Int_t j=1; j<=maxLr; j++) {
+    lr = GetLayer(j);
+    //    printf("Here0: %d\n",j);
+    if (!PropagateToLayer(&probeTmp,lr,1)) return 0;
+    if (j!=maxLr) if (!probeTmp.CorrectForMeanMaterial(lr, kFALSE)) return 0;
+    //    printf("Prelim. Err at lr:%8s | %7.3f %7.3f\n",lr->GetName(),TMath::Sqrt(probeTmp.GetSigmaY2()),TMath::Sqrt(probeTmp.GetSigmaZ2()));
+  }
+  for (Int_t j=maxLr; j>0; j--) {
+    lr = GetLayer(j);
+    //    printf("Here1: %d\n",j);
+    if (j!=maxLr) if (!PropagateToLayer(&probeTmp,lr,-1)) return 0;
+    lr->fSig2EstD = probeTmp.GetSigmaY2();
+    lr->fSig2EstZ = probeTmp.GetSigmaZ2();
+    //    probeTmp.Print("l");
+    printf("Natural Err at lr:%8s | %7.3f %7.3f\n",lr->GetName(),TMath::Sqrt(lr->fSig2EstD),TMath::Sqrt(lr->fSig2EstZ));
+    if (!probeTmp.CorrectForMeanMaterial(lr, kTRUE)) return 0;
+  }
+  // Store non-updated track errors of inward propagated seed <<<<<<<<
+  //
+  int nsm = sumArr ? sumArr->GetEntriesFast() : 0;
+  KMCLayer* vtx = GetLayer(0);
+  //
+  for (int i=0;i<nsm;i++) {
+    KMCTrackSummary* tsm = (KMCTrackSummary*)sumArr->At(i);
+    if (!tsm) continue;
+    tsm->SetRefProbe( GetProbeTrack() ); // attach reference track (generated)
+    tsm->SetAnProbe( vtx->GetAnProbe() ); // attach analitycal solution
+  }
+  //
+  TStopwatch sw;
+  sw.Start();
+  for (int it=0;it<nMC;it++) {
+    printf("ev: %d\n",it);
+    SolveSingleTrackViaKalmanMC(offset);
+    KMCProbe* trc = vtx->GetWinnerMCTrack();
+    vtx->GetMCTracks()->Print();
+    if (progressP==1 || (progressP>0 &&  (it%progressP)==0)) {
+      printf("%d%% done |",it*100/nMC); 
+      sw.Stop(); sw.Print(); sw.Start(kFALSE);
+    }
+    for (int ism=nsm;ism--;) { // account the track in each of summaries
+      KMCTrackSummary* tsm = (KMCTrackSummary*)sumArr->At(ism);
+      if (!tsm) continue;
+      tsm->AddUpdCalls(GetUpdCalls());
+      tsm->AddTrack(trc); 
+    }
+  }
+  //
+  sw.Stop();
+  printf("Total time: "); sw.Print();
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Int_t KMCDetector::GetLayerID(int actID) const
+{
+  // find physical layer id from active id
+  if (actID<0 || actID>fNActiveLayers) return -1;
+  int start = actID<fNActiveITSLayers ? fLastActiveITSLayer : fLastActiveLayer;
+  for (int i=start+1;i--;) {
+    if (GetLayer(i)->GetActiveID()==actID) return i;   
+  }
+  return -1;
+}
+
+//________________________________________________________________________________
+KMCProbe* KMCDetector::KalmanSmooth(int actLr, int actMin,int actMax) const
+{
+  // estimate kalman smoothed track params at given active lr 
+  // from fit at layers actMin:actMax (excluding actLr)
+  // SolveSingleTrackViaKalman must have been called before
+  //
+  if (actMin>actMax) swap(actMin,actMax);
+  if (actMax>=fNActiveLayers) actMax = fNActiveLayers-1;
+  int nlrfit = actMax-actMin;
+  if (actLr>=actMin && actLr<=actMax) nlrfit-=1;
+  if (nlrfit<2) {AliInfo("Need a least 2 active layers in the fit"); return 0;}
+  static KMCProbe iwd,owd;
+  //
+  // find phisical layer id's
+  int pLr  = GetLayerID(actLr);
+  int pMin = GetLayerID(actMin);
+  int pMax = GetLayerID(actMax);
+  //
+  //  printf(">>> %d %d %d\n",pLr, pMin,pMax);
+  Bool_t useIwd=kFALSE, useOwd=kFALSE;
+  if (pLr<pMax) { // need inward piece
+    iwd = GetLayer(pMax)->fTrCorr;
+    iwd.ResetCovMat();
+    iwd.GetHitsPatt() = 0;
+    for (int i=pMax;i>=pLr;i--) {
+      KMCLayer* lr = GetLayer(i);
+      //      printf("IWD %d\n",i);
+      if (!lr->IsDead() && i!=pLr && i>=pMin) if (!UpdateTrack(&iwd,lr,&lr->fClCorr))  return 0;
+      if (i!=pLr) {
+       if (!iwd.CorrectForMeanMaterial(lr,kTRUE)) return 0; // correct for materials of this layer
+       if (!PropagateToLayer(&iwd,GetLayer(i-1),-1)) return 0;      // propagate to next layer
+      }
+      //  printf("IWD%d:  ",i); iwd.Print("l");
+    }
+    useIwd = kTRUE;
+  }
+  if (pLr>pMin) { // need outward piece
+    owd = GetLayer(pMin)->fTrCorr;
+    owd.ResetCovMat();
+    owd.GetHitsPatt() = 0;
+    for (int i=pMin;i<=pLr;i++) {
+      KMCLayer* lr = GetLayer(i);
+      //      printf("OWD %d\n",i);
+      if (!lr->IsDead() && i!=pLr && i<=pMax) if (!UpdateTrack(&owd,lr,&lr->fClCorr))  return 0;
+      if (i!=pLr) {
+       if (!owd.CorrectForMeanMaterial(lr,0)) return 0; // correct for materials of this layer
+       if (!PropagateToLayer(&owd,GetLayer(i+1), 1)) return 0;      // propagate to next layer
+      }
+      //      printf("OWD%d:  ",i); owd.Print("l");
+    }
+    useOwd = kTRUE;
+  }
+  //
+  // was this extrapolation outside the fit range?
+  if (!useIwd) return (KMCProbe*)&owd; 
+  if (!useOwd) return (KMCProbe*)&iwd;
+  //
+  // weight both tracks
+  if (!iwd.Propagate(owd.GetAlpha(),owd.GetX(),fBFieldG)) return 0;
+  double meas[2] = {owd.GetY(),owd.GetZ()};
+  double measErr2[3] = {owd.GetSigmaY2(), owd.GetSigmaZY(), owd.GetSigmaZ2()};
+  //  printf("Weighting\n");
+  //  owd.Print("l");
+  //  iwd.Print("l");
+  if (!iwd.Update(meas,measErr2)) return 0;
+  iwd.GetHitsPatt() |= owd.GetHitsPatt();
+
+  //  printf("->\n");
+  //  iwd.Print("l");
+
+  return (KMCProbe*)&iwd;
+  //
+}
+
+//________________________________________________________________________________
+KMCProbe* KMCDetector::KalmanSmoothFull(int actLr, int actMin,int actMax) const
+{
+  // estimate kalman smoothed track params at given active lr 
+  // from fit at layers actMin:actMax (excluding actLr)
+  // SolveSingleTrackViaKalman must have been called before
+  //
+  static TClonesArray prediction("KMCProbe",10);
+  static TClonesArray update("KMCProbe",10);
+  static KMCProbe res;
+  //
+  if (actMin>actMax) swap(actMin,actMax);
+  int nlrfit = actMax-actMin;
+  if (actLr>=actMin && actLr<=actMax) nlrfit-=1;
+  if (nlrfit<2) {AliInfo("Need a least 2 active layers in the fit"); return 0;}
+  //
+  // find phisical layer id's
+  int pLr  = GetLayerID(actLr);
+  int pMin = GetLayerID(actMin);
+  int pMax = GetLayerID(actMax);
+  //
+  int dir=0,dirInt=0;
+  if      (pLr<=pMin) dir=-1; // inward extrapolation
+  else if (pLr>=pMax) dir= 1; // outward extrapolation
+  else if (actMax-actLr >= actLr-actMin) dirInt = -1; // inward  interpolation (the test point is closer to inner layer)
+  else    dirInt = 1;                                 // outward interpolation (the test point is closer to outer layer)
+  //
+  if (dir!=0) { // no sens to do smoothing: simple Kalman filtering extrapolation
+    int start = dir<0 ? pMax : pMin;
+    res = GetLayer(start)->fTrCorr;
+    res.ResetCovMat();
+    KMCLayer* lr = 0;
+    for (int i=(dir<0?pMax:pMin); i!=pLr; i+=dir) { // track till nearest layer to pLr
+      lr = GetLayer(i);
+      if (!lr->IsDead() && !(i<pMin ||i>pMax)) if (!UpdateTrack(&res,lr,&lr->fClCorr))  return 0; // update only with layers in fit range
+      if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this layer
+      if (!PropagateToLayer(&res,GetLayer(i+dir),dir))            return 0; // propagate to next layer     
+    }
+    if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this nearest layer
+    if (!PropagateToLayer(&res,GetLayer(pLr), dir)) return 0; // propagate to test layer
+    return (KMCProbe*)&res;
+  }
+  //
+  // too bad, need to do real filtering
+  //
+  int start = dirInt<0 ? pMax : pMin;
+  int stop  = dirInt<0 ? pMin-1 : pMax+1;
+  res = GetLayer(start)->fTrCorr;
+  res.ResetCovMat();
+  KMCLayer* lr = 0;
+  int count = 0;
+  for (int i=start; i!=stop; i+=dirInt) { // track in full range, storing updates and predictions
+    new(prediction[count]) KMCProbe(res);
+    lr = GetLayer(i);
+    if (!lr->IsDead() && i!=pLr) if (!UpdateTrack(&res,lr,&lr->fClCorr))  return 0; // update only with layers in fit range
+    new(update[count]) KMCProbe(res);
+    if (!res.CorrectForMeanMaterial(lr,dir<0 ? kTRUE:kFALSE))   return 0; // correct for materials of this layer
+    if (!PropagateToLayer(&res,GetLayer(i+dir),dir))            return 0; // propagate to next layer     
+    count++;
+  }
+  return (KMCProbe*)&res;
+  //
+}
+
+//________________________________________________________________________________
+Bool_t KMCDetector::SolveSingleTrackViaKalman(Double_t mass, Double_t pt, Double_t eta)
+{
+  // analytical estimate of tracking resolutions
+  //  fProbe.SetUseLogTermMS(kTRUE);
+  //
+  if (fMinITSHits>fNActiveITSLayers) {fMinITSHits = fNActiveITSLayers; printf("Redefined request of min N ITS hits to %d\n",fMinITSHits);}
+  if (TMath::Abs(eta)<1e-3) fDensFactorEta = 1.;
+  else {
+    fDensFactorEta = TMath::Tan( 2.*TMath::ATan(TMath::Exp(-TMath::Abs(eta))) );
+    fDensFactorEta = 1./TMath::Sqrt( 1. + 1./fDensFactorEta/fDensFactorEta);
+  }
+  double lambda = TMath::Pi()/2.0 - 2.0*TMath::ATan(TMath::Exp(-eta)); 
+  KMCProbe* probe = PrepareKalmanTrack(pt,lambda,mass,-1);
+  if (!probe) return kFALSE;
+  //
+  KMCLayer *lr = 0;
+  //
+  //
+  // Start the track fitting --------------------------------------------------------
+  //
+  // Back-propagate the covariance matrix along the track. 
+  // Kalman loop over the layers
+  //
+  KMCProbe* currTr = 0;
+  lr = (KMCLayer*)fLayers.At(fLastActiveLayerTracked);
+  lr->fTrCorr = *probe;
+  delete probe; // rethink...
+  //
+  for (Int_t j=fLastActiveLayerTracked; j--; ) {  // Layer loop
+    //
+    KMCLayer *lrP = lr;
+    lr = (KMCLayer*)fLayers.At(j);
+    //
+    lr->fTrCorr = lrP->fTrCorr;
+    currTr = &lr->fTrCorr;
+    currTr->ResetHit(lrP->GetActiveID());
+    //
+    // if there was a measurement on prev layer, update the track
+    if (!lrP->IsDead()) { // include measurement
+      KMCCluster cl(currTr->GetY(),currTr->GetZ(), currTr->GetX(), currTr->GetAlpha());
+      if (!UpdateTrack(currTr,lrP,&cl))  return kFALSE;
+    }
+    if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) return kFALSE; // correct for materials of this layer
+    if (!PropagateToLayer(currTr,lr,-1)) return kFALSE;      // propagate to current layer
+    //
+  } // end loop over layers
+  //
+  return kTRUE;
+}
+
+//____________________________________________________________
+Bool_t KMCDetector::SolveSingleTrackViaKalmanMC(int offset)
+{
+  // MC estimate of tracking resolutions/effiencies. Requires that the SolveSingleTrackViaKalman
+  // was called before, since it uses data filled by this method
+  //
+  // The MC tracking will be done starting from fLastActiveITSLayer + offset (before analytical estimate will be used)
+  //
+  // At this point, the fProbe contains the track params generated at vertex.
+  // Clone it and propagate to target layer to generate hit positions affected by MS
+  //
+  fUpdCalls = 0.;
+  KMCProbe *currTrP=0,*currTr=0;
+  int maxLr = fLastActiveITSLayer + offset;
+  if (maxLr >= fLastActiveLayerTracked-1) maxLr = fLastActiveLayerTracked;
+  ResetMCTracks(maxLr);
+  KMCLayer* lr = (KMCLayer*)fLayers.At(maxLr);
+  currTr = lr->AddMCTrack(&fProbe); // start with original track at vertex
+  //
+  if (!TransportKalmanTrackWithMS(currTr, maxLr)) return kFALSE; // transport it to outermost layer where full MC is done
+  //
+  if (fLastActiveITSLayer<fLastActiveLayerTracked) { // prolongation from TPC
+    // start from correct track propagated from above till maxLr
+    double *covMS = (double*)currTr->GetCovariance();
+    const double *covIdeal =lr->fTrCorr.GetCovariance();
+    for (int i=15;i--;) covMS[i] = covIdeal[i];
+  }
+  else { // ITS SA: randomize the starting point
+    //    double *pars = (double*)currTr->GetParameter();
+    //    pars[0] += gRandom->Gaus(0,TMath::Sqrt(currTr->GetSigmaY2()));
+    //    pars[1] += gRandom->Gaus(0,TMath::Sqrt(currTr->GetSigmaZ2()));
+    //
+    currTr->ResetCovMat();
+    /*
+    double *trCov  = (double*)currTr->GetCovariance();
+    double *trPars = (double*)currTr->GetParameter();
+    const double kLargeErr2PtI = 0.3*0.3;
+    trCov[14] = TMath::Max(trCov[14],kLargeErr2PtI*trPars[4]*trPars[4]);
+    */
+  }
+  //
+  for (Int_t j=maxLr; j--; ) {  // Layer loop
+    //
+    KMCLayer *lrP = lr;
+    lr = (KMCLayer*)fLayers.At(j);
+    int ntPrev = lrP->GetNMCTracks();
+    //
+    if (lrP->IsDead()) { // for passive layer just propagate the copy of all tracks of prev layer >>>
+      for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer
+       currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;
+       currTr = lr->AddMCTrack( currTrP );
+       if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill(); continue;} // correct for materials of prev. layer
+       if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill(); continue;} // propagate to current layer
+      }
+      continue;
+    } // treatment of dead layer <<<
+    //
+    if (lrP->IsTPC()) { // we don't consider bg hits in TPC, just update with MC cluster
+      for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer
+       currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;
+       currTr = lr->AddMCTrack( currTrP );
+       if (!UpdateTrack(currTr, lrP, lrP->GetMCCluster(), kTRUE)) {currTr->Kill(); continue;} // update with correct MC cl.
+       if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill(); continue;} // correct for materials of prev. layer
+       if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill(); continue;} // propagate to current layer
+      }
+      continue;
+    } // treatment of ideal (TPC?) layer <<<
+    //
+    // active layer under eff. study (ITS?): propagate copy of every track to MC cluster frame (to have them all in the same frame)
+    // and calculate the limits of bg generation
+    KMCCluster* clMC = lrP->GetMCCluster();
+    if (lrP->GetLayerEff()<gRandom->Rndm()) clMC->Kill(); // simulate inefficiency
+    ResetSearchLimits();
+    int nseeds = 0;
+    for (int itrP=ntPrev;itrP--;) { // loop over all tracks from previous layer
+      currTrP = lrP->GetMCTrack(itrP); if (currTrP->IsKilled()) continue;
+      currTr = lr->AddMCTrack( currTrP );
+      if (!currTr->PropagateToCluster(clMC,fBFieldG)) {currTr->Kill(); continue;} // go to MC cluster
+      if ( !(currTr->GetNITSHits()>0 && currTr->GetNITSHits()==currTr->GetNFakeITSHits()) ) UpdateSearchLimits(currTr, lrP); // RS
+      nseeds++;
+    }
+    //
+    //    printf("%3d seeds\n",nseeds);
+    if (fUseBackground && lrP->IsITS()) GenBgClusters(lrP); //  generate background hits
+    //
+    ntPrev = lr->GetNMCTracks();
+    for (int itr=ntPrev;itr--;) { // loop over all tracks PROPAGATED from previous layer to clusters frame on previous layer
+      currTrP = lr->GetMCTrack(itr); // this is a seed from prev layer. The new clusters are attached to its copies, the seed itself
+                                     // will be propagated w/o cluster update if it does not violate requested "reconstructed" track settings
+      if (currTrP->IsKilled()) continue;
+      //printf("Check    %d %p %d\n",itr,currTrP,currTrP->GetUniqueID()); currTrP->Print();
+      CheckTrackProlongations(currTrP, lr, lrP);
+      if (NeedToKill(currTrP)) currTrP->Kill(); // kill track which was not updated at lrP
+      //currTrP->Kill(); // kill track which was not updated at lrP
+    }
+    //  
+    lr->GetMCTracks()->Sort();
+    int ntTot = lr->GetNMCTracks(); // propagate max amount of allowed tracks to current layer
+    if (ntTot>fMaxSeedToPropagate && fMaxSeedToPropagate>0) {
+      for (int itr=ntTot;itr>=fMaxSeedToPropagate;itr--)  lr->GetMCTracks()->RemoveAt(itr);
+      ntTot = fMaxSeedToPropagate;
+    }
+    //
+    for (int itr=ntTot;itr--;) {
+      currTr = lr->GetMCTrack(itr);
+      if (!currTr->CorrectForMeanMaterial(lrP,kTRUE)) {currTr->Kill();continue;} // correct for materials of prev. layer
+      if (!PropagateToLayer(currTr,lr,-1))      {currTr->Kill();continue;} // propagate to current layer
+    }
+    AliDebug(1,Form("Got %d tracks on layer %s",ntTot,lr->GetName()));
+    //    lr->GetMCTracks()->Print();
+    //
+  } // end loop over layers    
+  //
+  // do we use vertex constraint?
+  KMCLayer *vtx = GetLayer(0);
+  if (!vtx->IsDead() && vtx->IsITS()) {
+    int ntr = vtx->GetNMCTracks();
+    for (int itr=0;itr<ntr;itr++) {
+      currTr = vtx->GetMCTrack(itr);
+      if (currTr->IsKilled()) continue;
+      KMCCluster* clv = vtx->GetMCCluster();
+      double meas[2] = {clv->GetY(),clv->GetZ()};
+      double measErr2[3] = {vtx->fPhiRes*vtx->fPhiRes,0,vtx->fZRes*vtx->fZRes};
+      double chi2v = currTr->GetPredictedChi2(meas,measErr2);
+      currTr->AddHit(vtx->GetActiveID(), chi2v, -1);
+      currTr->SetInnerLrChecked(vtx->GetActiveID());
+      if (NeedToKill(currTr)) currTr->Kill();
+      // if (vtx->IsITS()) {if (!UpdateTrack(currTr, vtx, vtx->GetMCCluster(), kFALSE)) {currTr->Kill();continue;}}
+    }
+  }
+  EliminateUnrelated();
+  
+  return kTRUE;
+}
+
+//____________________________________________________________________________
+Bool_t KMCDetector::PropagateToLayer(KMCProbe* trc, KMCLayer* lr, int dir) const
+{
+  // bring the track to layer and rotat to frame normal to its surface
+  if (!trc->PropagateToR(lr->fR,fBFieldG, dir)) return kFALSE;
+  //
+  // rotate to frame with X axis normal to the surface (defined by ideal track)
+  if (!lr->IsVertex()) {
+    double pos[3];
+    trc->GetXYZ(pos);  // lab position
+    double phi = TMath::ATan2(pos[1],pos[0]);
+    if ( TMath::Abs(TMath::Abs(phi)-TMath::Pi()/2)<1e-3) phi = 0;
+    if (!trc->Rotate(phi)) {
+      AliDebug(2,Form("Failed to rotate to the frame (phi:%+.3f) of layer at %.2f at XYZ: %+.3f %+.3f %+.3f",
+                     phi,lr->fR,pos[0],pos[1],pos[2]));
+      if (AliLog::GetGlobalDebugLevel()>1) trc->Print("l");
+      return kFALSE;
+    }
+  }
+  //
+  return kTRUE;
+}
+
+//____________________________________________________________________________
+Bool_t KMCDetector::UpdateTrack(KMCProbe* trc, KMCLayer* lr, KMCCluster* cl, Bool_t goToCluster) const
+{
+  // update track with measured cluster
+  // propagate to cluster
+  double meas[2] = {cl->GetY(),cl->GetZ()}; // ideal cluster coordinate
+  double measErr2[3] = {lr->fPhiRes*lr->fPhiRes,0,lr->fZRes*lr->fZRes};
+  //
+  if (goToCluster) if (!trc->PropagateToCluster(cl,fBFieldG)) return kFALSE; // track was not propagated to cluster frame
+  //
+  double chi2 = trc->GetPredictedChi2(meas,measErr2);
+  //  if (chi2>fMaxChi2Cl) return kTRUE; // chi2 is too large
+  //  
+  if (!trc->Update(meas,measErr2)) {
+    AliDebug(2,Form("layer %s: Failed to update the track by measurement {%.3f,%3f} err {%.3e %.3e %.3e}",
+                   lr->GetName(),meas[0],meas[1], measErr2[0],measErr2[1],measErr2[2]));
+    if (AliLog::GetGlobalDebugLevel()>1) trc->Print("l");
+    return kFALSE;
+  }
+  trc->AddHit(lr->GetActiveID(), chi2);
+  //
+  return kTRUE;
+}
+
+//____________________________________________________________________________
+Int_t KMCDetector::GenBgClusters(KMCLayer* lr)
+{
+  // Generate fake clusters in precalculated RPhi,Z range
+  if (fNBgLimits<1) return 0; // limits were not set - no track was prolongated
+  //
+  // Fix search limits to avoid seeds which will anyway point very far from the vertex
+  double tolY = TMath::Sqrt(lr->fSig2EstD)*fMaxChi2ClSQ;
+  double tolZ = TMath::Sqrt(lr->fSig2EstZ)*fMaxChi2ClSQ;
+  
+  //  printf("Before: Y: %+6.3f : %+6.3f tolY: %6.3f || Z: %+6.3f : %+6.3f tolZ: %6.3f\n",fBgYMin,fBgYMax,tolY, fBgZMin,fBgZMax,tolZ);
+  if (fBgYMin < lr->fClCorr.fY-tolY) fBgYMin = lr->fClCorr.fY-tolY;
+  if (fBgYMax > lr->fClCorr.fY+tolY) fBgYMax = lr->fClCorr.fY+tolY;
+  if (fBgZMin < lr->fClCorr.fZ-tolZ) fBgZMin = lr->fClCorr.fZ-tolZ;
+  if (fBgZMax > lr->fClCorr.fZ+tolZ) fBgZMax = lr->fClCorr.fZ+tolZ;
+  //printf("After: Y: %+6.3f : %+6.3f tolY: %6.3f || Z: %+6.3f : %+6.3f tolZ: %6.3f\n",fBgYMin,fBgYMax,tolY, fBgZMin,fBgZMax,tolZ);
+  //
+  double dy = fBgYMax - fBgYMin;
+  double dz = fBgZMax - fBgZMin;
+  double surf = dy*dz;               // surface of generation
+  if (surf<0) return 0;
+  double poissProb = surf*HitDensity(lr->fR)*lr->GetLayerEff();
+  AliDebug(2,Form("Bg for Lr %s (r=%.2f) : Density %.2f on surface %.2e [%+.4f : %+.4f][%+.4f %+.4f]",
+                 lr->GetName(),lr->fR,HitDensity(lr->fR),surf,fBgYMin,fBgYMax,fBgZMin,fBgZMax));
+  int nFakesGen = gRandom->Poisson( poissProb ); // preliminary number of extra clusters to test
+  KMCCluster *refCl = lr->GetMCCluster();
+  double sig2y = lr->GetPhiRes()*lr->GetPhiRes();
+  double sig2z = lr->GetZRes()*lr->GetZRes();
+  for (int ic=nFakesGen;ic--;) {
+    double y = fBgYMin+dy*gRandom->Rndm();
+    double z = fBgZMin+dz*gRandom->Rndm();
+    double dfy = y-refCl->GetY();
+    double dfz = z-refCl->GetZ();
+    double dist = (dfy*dfy)/sig2y + (dfz*dfz)/sig2z;
+    if (dist<4) continue; // avoid overlap with MC cluster
+    lr->AddBgCluster(y, z, refCl->GetX(), refCl->GetPhi());
+  }
+  AliDebug(2,Form("Added %6d noise clusters on lr %s (poisson Prob=%8.2f for surface %.2e) DY:%7.4f DZ: %7.4f",
+                  lr->GetNBgClusters(),lr->GetName(),poissProb,surf,dy,dz));
+  return nFakesGen;
+  //
+}
+
+//____________________________________________________________________________
+void KMCDetector::UpdateSearchLimits(KMCProbe* probe, KMCLayer* lr)
+{
+  // define the search window for track on layer (where the bg hist will be generated)
+  static double *currYMin = fBgYMinTr.GetArray();
+  static double *currYMax = fBgYMaxTr.GetArray();
+  static double *currZMin = fBgZMinTr.GetArray();
+  static double *currZMax = fBgZMaxTr.GetArray();
+  //
+  double sizeY = probe->GetSigmaY2(), sizeZ = probe->GetSigmaZ2();
+  //  /*
+  if (probe->GetNITSHits()<3) sizeY = 10*lr->fSig2EstD;
+  if (probe->GetNITSHits()<2) sizeZ = 10*lr->fSig2EstZ;
+  sizeY = fMaxChi2ClSQ*TMath::Sqrt(sizeY+lr->fPhiRes*lr->fPhiRes); // max deviation in rphi to accept
+  sizeZ = fMaxChi2ClSQ*TMath::Sqrt(sizeZ+lr->fZRes*lr->fZRes); // max deviation in dz to accept
+  //  */
+  //
+  /*
+  if (probe->GetNITSHits()<3) sizeY = 1./(1./lr->fSig2EstD + 1./sizeY);
+  if (probe->GetNITSHits()<2) sizeZ = 1./(1./lr->fSig2EstZ + 1./sizeZ);
+  sizeY = fMaxChi2ClSQ*TMath::Sqrt(sizeY); // max deviation in rphi to accept
+  sizeZ = fMaxChi2ClSQ*TMath::Sqrt(sizeZ); // max deviation in dz to accept
+  */
+  //
+  //  if (sizeY>2) sizeY=2;
+  //  if (sizeZ>2) sizeZ=2;
+  //  printf("Sizes at %s: %.5f %.5f\n",lr->GetName(), sizeY,sizeZ);
+  //
+  if (fNBgLimits>=fBgYMinTr.GetSize()) { // expand arrays, update pointers
+    fBgYMinTr.Set(2*(fNBgLimits+1));
+    fBgYMaxTr.Set(2*(fNBgLimits+1));
+    fBgZMinTr.Set(2*(fNBgLimits+1));
+    fBgZMaxTr.Set(2*(fNBgLimits+1));
+    currYMin = fBgYMinTr.GetArray();
+    currYMax = fBgYMaxTr.GetArray();
+    currZMin = fBgZMinTr.GetArray();
+    currZMax = fBgZMaxTr.GetArray();
+  }
+  if (fBgYMin > (currYMin[fNBgLimits]=probe->GetY()-sizeY) ) fBgYMin = currYMin[fNBgLimits];
+  if (fBgYMax < (currYMax[fNBgLimits]=probe->GetY()+sizeY) ) fBgYMax = currYMax[fNBgLimits];
+  if (fBgZMin > (currZMin[fNBgLimits]=probe->GetZ()-sizeZ) ) fBgZMin = currZMin[fNBgLimits];
+  if (fBgZMax < (currZMax[fNBgLimits]=probe->GetZ()+sizeZ) ) fBgZMax = currZMax[fNBgLimits];
+  if (AliLog::GetGlobalDebugLevel()>=2) {
+    probe->Print("l");
+    AliInfo(Form("Seed%3d Lr %s limits for y:%+8.4f z:%+8.4f [%+.4f : %+.4f][%+.4f %+.4f]",fNBgLimits,lr->GetName(),probe->GetY(),probe->GetZ(),currYMin[fNBgLimits],currYMax[fNBgLimits],currZMin[fNBgLimits],currZMax[fNBgLimits]));
+    AliInfo(Form("Global Limits Lr %s                            [%+.4f : %+.4f][%+.4f %+.4f]",lr->GetName(),fBgYMin,fBgYMax,fBgZMin,fBgZMax));
+    AliInfo(Form("MC Cluster: %+.4f : %+.4f",lr->fClMC.fY, lr->fClMC.fZ));
+  }
+  probe->SetUniqueID(fNBgLimits++);
+  //
+  if (lr->IsITS() && probe->GetNFakeITSHits()==0) {
+    if (fHMCLrResidRPhi) fHMCLrResidRPhi->Fill(probe->GetY() - lr->GetMCCluster()->GetY(), lr->GetActiveID());
+    if (fHMCLrResidZ)    fHMCLrResidZ->Fill(probe->GetZ() - lr->GetMCCluster()->GetZ(),lr->GetActiveID());
+  }
+  //
+}
+
+//____________________________________________________________________________
+void KMCDetector::CheckTrackProlongations(KMCProbe *probe, KMCLayer* lr, KMCLayer* lrP)
+{
+  // explore prolongation of probe from lrP to lr with all possible clusters of lrP
+  // the probe is already brought to clusters frame
+  int nCl = lrP->GetNBgClusters();
+  double measErr2[3] = {lrP->fPhiRes*lrP->fPhiRes,0,lrP->fZRes*lrP->fZRes};
+  double meas[2] = {0,0};
+  UInt_t tmpID = probe->GetUniqueID();
+  double yMin = fBgYMinTr[tmpID];
+  double yMax = fBgYMaxTr[tmpID];
+  double zMin = fBgZMinTr[tmpID];
+  double zMax = fBgZMaxTr[tmpID];
+  //
+  probe->SetInnerLrChecked(lrP->GetActiveID());
+  for (int icl=-1;icl<nCl;icl++) {
+    KMCCluster* cl = icl<0 ? lrP->GetMCCluster() : lrP->GetBgCluster(icl);  // -1 is for true MC cluster
+    if (cl->IsKilled()) {
+      if (AliLog::GetGlobalDebugLevel()>1) {printf("Skip cluster %d ",icl); cl->Print();}
+      continue;
+    }
+    double y = cl->GetY();
+    double z = cl->GetZ();
+    AliDebug(2,Form("Check seed%d against cl#%d out of %d at layer %s | y:%+8.4f z:%+8.4f [%+.4f:%+.4f]  [%+.4f:%+.4f]",tmpID,icl,nCl,lrP->GetName(),y,z,yMin,yMax,zMin,zMax));
+    if (AliLog::GetGlobalDebugLevel()>0) {
+      if (icl==-1 && probe->GetNFakeITSHits()==0) {
+       meas[0] = y; meas[1] = z;
+       double chi2a = probe->GetPredictedChi2(meas,measErr2);
+       if (chi2a>fMaxChi2Cl || (y<yMin || y>yMax) || (z<zMin || z>zMax)) {
+         probe->Print();
+         printf("Loosing good point (y:%+8.4f z:%+8.4f) on lr %s: chi2: %.2f  | dy:%+8.4f dz:%+8.4f [%+.4f:%+.4f]  [%+.4f:%+.4f] |x: %.2f %.2f | phi: %.2f %.2f\n",
+                y,z,lrP->GetName(),chi2a,y-probe->GetY(),z-probe->GetZ(),yMin,yMax,zMin,zMax, probe->GetX(), cl->GetX(), probe->GetAlpha(), cl->GetPhi());
+       }
+      }
+    }
+    if (y<yMin || y>yMax) continue; // preliminary check on Y
+    if (z<zMin || z>zMax) continue; // preliminary check on Z
+    meas[0] = y; meas[1] = z;
+    double chi2 = probe->GetPredictedChi2(meas,measErr2);
+    if (fHMCLrChi2 && probe->GetNFakeITSHits()==0 && icl==-1) fHMCLrChi2->Fill(chi2,lrP->GetActiveID());
+    AliDebug(2,Form("Seed-to-cluster chi2 = Chi2=%.2f",chi2));
+    if (chi2>fMaxChi2Cl) continue;
+    // 
+    // update track copy
+    KMCProbe* newTr = lr->AddMCTrack( probe );
+    fUpdCalls++;
+    if (!newTr->Update(meas,measErr2)) {
+      AliDebug(2,Form("Layer %s: Failed to update the track by measurement {%.3f,%3f} err {%.3e %.3e %.3e}",
+                     lrP->GetName(),meas[0],meas[1], measErr2[0],measErr2[1],measErr2[2]));
+      if (AliLog::GetGlobalDebugLevel()>1) newTr->Print("l");
+      newTr->Kill();
+      continue;
+    }
+    newTr->AddHit(lrP->GetActiveID(), chi2, icl);
+    if (AliLog::GetGlobalDebugLevel()>1) {
+      AliInfo("Cloned updated track is:");
+      newTr->Print();
+    }
+    if (NeedToKill(newTr)) newTr->Kill();
+  }
+  //
+}
+
+//____________________________________________________________________________
+void KMCDetector::ResetMCTracks(Int_t maxLr)
+{
+  int nl = GetNLayers();
+  if (maxLr<0 || maxLr>=nl) maxLr = nl-1;
+  for (int i=maxLr+1;i--;) GetLayer(i)->ResetMCTracks();
+}
+
+//____________________________________________________________________________
+Bool_t KMCDetector::NeedToKill(KMCProbe* probe) const
+{
+  // check if the seed at given layer (last one where update was tried) 
+  // still has chances to be reconstructed
+  const Bool_t kModeKillMiss = kFALSE;
+  //
+  Bool_t kill = kFALSE;
+  while (1) {
+    int il = probe->GetInnerLayerChecked();
+    int nITS = probe->GetNITSHits();
+    int nITSMax = nITS + il; // maximum it can have
+    if (nITSMax<fMinITSHits) {
+      kill = kTRUE; 
+      break;
+    }    // has no chance to collect enough ITS hits
+    //
+    int ngr = fPattITS.GetSize();
+    if (ngr>0) { // check pattern
+      UInt_t patt = probe->GetHitsPatt();
+      // complete the layers not checked yet
+      for (int i=il;i--;) patt |= (0x1<<i);
+      for (int ig=ngr;ig--;) 
+       if (!(((UInt_t)fPattITS[ig]) & patt)) {
+         kill = kTRUE; 
+         break;
+       }
+      //
+    }
+    //
+    if (nITS>2) {  // check if smallest possible norm chi2/ndf is acceptable
+      double chi2min = probe->GetChi2();
+      if (kModeKillMiss) {
+       int nMiss = fNActiveITSLayers - probe->GetInnerLayerChecked() - nITS; // layers already missed
+       chi2min = nMiss*probe->GetMissingHitPenalty();
+      }
+      chi2min /= ((nITSMax<<1)-KMCProbe::kNDOF);
+      if (chi2min>fMaxNormChi2NDF) {
+       kill = kTRUE; 
+       break;
+      }
+    }
+    //
+    // loose vertex constraint
+    double dst;
+    if (nITS>=2) {
+      probe->GetZAt(0,fBFieldG,dst);
+      //printf("Zd (F%d): %f\n",probe->GetNFakeITSHits(),dst);
+      if (TMath::Abs(dst)>10.) {
+       kill = kTRUE; 
+       break;
+      }
+    }
+    if (nITS>=3) {
+      probe->GetYAt(0,fBFieldG,dst);
+      //printf("Dd (F%d): %f\n",probe->GetNFakeITSHits(),dst);
+      if (TMath::Abs(dst)>10.) {
+       kill = kTRUE; 
+       break;
+      }
+    }
+    //
+    break;
+  }
+  if (kill && AliLog::GetGlobalDebugLevel()>1 && probe->GetNFakeITSHits()==0) {
+    printf("Killing good seed, last upd layer was %d\n",probe->GetInnerLayerChecked());
+    probe->Print("l");
+  }
+  return kill;
+}
+
+//_____________________________________________________________________
+void KMCDetector::EliminateUnrelated()
+{
+  // kill useless tracks
+  KMCLayer* lr = GetLayer(0);
+  int ntr = lr->GetNMCTracks();
+  int nval = 0;
+  for (int itr=0;itr<ntr;itr++) {
+    KMCProbe* probe = lr->GetMCTrack(itr);
+    if (probe->IsKilled()) continue;
+    if (probe->GetNITSHits()-probe->GetNFakeITSHits()<1) {probe->Kill(); continue;}
+    nval++;
+  }
+  lr->GetMCTracks()->Sort();
+  const int kDump = 0;
+  if (kDump>0) {
+    printf("Valid %d out of %d\n",nval, ntr);
+    ntr = ntr>kDump ? kDump:0;
+    for (int itr=0;itr<ntr;itr++) {
+      lr->GetMCTrack(itr)->Print();
+    }
+  }
+}
+
+//_____________________________________________________________________
+void KMCDetector::RequirePattern(UInt_t *patt, int groups)
+{
+  if (groups<1) {fPattITS.Set(0); return;}
+  fPattITS.Set(groups);
+  for (int i=0;i<groups;i++) fPattITS[i] = patt[i];
+}
+
+//_____________________________________________________________________
+void KMCDetector::CalcHardSearchLimits(double dzv)
+{
+  //
+  TArrayD zlims;
+  zlims.Set(fNActiveITSLayers);
+  for (int il0=0;il0<fNActiveITSLayers;il0++) {
+    KMCLayer* lr0 = GetActiveLayer(il0);
+    double angZTol = dzv/lr0->GetRadius();
+    for (int il1=0;il1<fNActiveITSLayers;il1++) {
+      if (il1==il0) continue;
+      KMCLayer* lr1 = GetActiveLayer(il1);
+      double ztol = angZTol*TMath::Abs(lr0->GetRadius() - lr1->GetRadius());
+      if (ztol>zlims[il1]) zlims[il1] = ztol;
+    }
+  }
+  //
+  for (int il=0;il<fNActiveITSLayers;il++) printf("ZTol%d: %8.4f\n",il,zlims[il]);
+}
+
+//_______________________________________________________
+double KMCDetector::PropagateBack(KMCProbe* trc) 
+{
+  static KMCProbe bwd;
+  bwd = *trc;
+  bwd.ResetCovMat();
+  static double measErr2[3] = {0,0,0};
+  static double meas[2] = {0,0};
+  int icl = 0;
+  double chi2Tot = 0;
+  for (int il=1;il<=fLastActiveITSLayer;il++) {
+    KMCLayer* lr = GetLayer(il);
+    if (!PropagateToLayer(&bwd,lr,1)) return -1;
+    int aID = lr->GetActiveID();
+    if (aID>-1 && (icl=bwd.fClID[aID])>=-1) {
+      KMCCluster* clMC =  icl<0 ? lr->GetMCCluster() : lr->GetBgCluster(icl);
+      if (!bwd.PropagateToCluster(clMC,fBFieldG)) return -1;
+      meas[0] = clMC->GetY(); meas[1] = clMC->GetZ();
+      measErr2[0] = lr->fPhiRes*lr->fPhiRes;
+      measErr2[2] = lr->fZRes*lr->fZRes;
+      double chi2a = bwd.GetPredictedChi2(meas,measErr2);
+      chi2Tot += chi2a;
+      printf("Chis %d (cl%+3d): t2c: %6.3f tot: %6.3f\n",aID,icl,chi2a, chi2Tot);
+      bwd.Update(meas,measErr2);
+      bwd.AddHit(aID, chi2a, icl);     
+    }
+    if (!bwd.CorrectForMeanMaterial(lr,kFALSE)) return -1;
+  }
+  return chi2Tot;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------
+ClassImp(KMCTrackSummary)
+
+Int_t KMCTrackSummary::fgSumCounter = 0;
+
+//____________________________________________________________________________
+KMCTrackSummary::KMCTrackSummary(const char* name,const char* title, int nlr) :
+  TNamed(name,name), fNITSLayers(nlr),
+  fPattITS(0),fPattITSFakeExcl(0),fPattITSCorr(0),
+  fHMCChi2(0),fHMCSigDCARPhi(0),fHMCSigDCAZ(0),fHMCSigPt(0),fHMCNCl(0),fHMCFakePatt(0),
+  fCountAcc(0),fCountTot(0),fUpdCalls(0),
+  fRefProbe(),fAnProbe()
+{
+  // create summary structure for specific track conditions
+  //
+  SetMinMaxClITS();
+  SetMinMaxClITSFake();
+  SetMinMaxClITSCorr();
+  //
+  if (name==0 && title==0 && nlr==0) return;  // default dummy contructor
+  //
+  enum {kNBinRes=1000};
+  const double kMaxChi2(10),kMaxResRPhi=0.1, kMaxResZ=0.1,kMaxResPt=0.3;
+  //
+  TString strN = name, strT = title;
+  if (strN.IsNull()) strN = Form("TrSum%d",fgSumCounter);
+  if (strT.IsNull()) strT = strN;
+  fgSumCounter++;
+  //
+  if (fNITSLayers<1) {
+    fNITSLayers=KMCProbe::GetNITSLayers(); 
+    if (fNITSLayers<1) {AliError("N ITS layer is not provided and not available from KMCProbe::GetNITSLayers()"); exit(1);}
+    AliInfo(Form("%s No N Layers provided, set %d",strN.Data(),fNITSLayers));
+  }
+  nlr = fNITSLayers;
+  //
+  TString nam,tit;
+  //
+  nam = Form("%s_mc_chi2",strN.Data());
+  tit = Form("%s MC #chi^{2}",strT.Data());
+  fHMCChi2 = new TH1F(nam.Data(),tit.Data(),kNBinRes,0,kMaxChi2);
+  fHMCChi2->GetXaxis()->SetTitle("#chi^{2}");
+  fHMCChi2->Sumw2();
+  //
+  nam = Form("%s_mc_DCArphi",strN.Data());
+  tit = Form("%s MC #DeltaDCA r#phi",strT.Data());
+  fHMCSigDCARPhi = new TH1F(nam.Data(),tit.Data(),kNBinRes,-kMaxResRPhi,kMaxResRPhi);
+  fHMCSigDCARPhi->GetXaxis()->SetTitle("#Delta r#phi");
+  fHMCSigDCARPhi->Sumw2();
+  //
+  nam = Form("%s_mc_DCAz",strN.Data());
+  tit = Form("%s MC #DeltaDCA Z",strT.Data());
+  fHMCSigDCAZ = new TH1F(nam.Data(),tit.Data(),kNBinRes,-kMaxResZ,kMaxResZ);
+  fHMCSigDCAZ->GetXaxis()->SetTitle("#Delta Z");
+  fHMCSigDCAZ->Sumw2();
+  //
+  nam = Form("%s_mc_pt",strN.Data());
+  tit = Form("%s MC $Deltap_{T}/p_{T}",strT.Data());
+  fHMCSigPt = new TH1F(nam.Data(),tit.Data(),2*kNBinRes,-kMaxResPt,kMaxResPt);
+  fHMCSigPt->GetXaxis()->SetTitle("#Deltap_{T}/p_{T}");
+  fHMCSigPt->Sumw2();
+  //
+  nam = Form("%s_n_cl",strN.Data());
+  tit = Form("%s N Clusters",strT.Data());
+  fHMCNCl = new TH2F(nam.Data(),tit.Data(),nlr,1,nlr+1,nlr,1,nlr+1);
+  fHMCNCl->GetXaxis()->SetTitle("N Clusters Tot");
+  fHMCNCl->GetYaxis()->SetTitle("N Clusters Fake");
+  fHMCNCl->Sumw2();
+  //
+  nam = Form("%s_fake_cl",strN.Data());
+  tit = Form("%s Fake Clusters",strT.Data());
+  fHMCFakePatt = new TH1F(nam.Data(),tit.Data(),nlr,-0.5,nlr-0.5);
+  fHMCFakePatt->GetXaxis()->SetTitle("Fake clusters pattern");
+  fHMCFakePatt->Sumw2();
+  //
+}
+
+//____________________________________________________________________________
+KMCTrackSummary::~KMCTrackSummary()
+{
+  if (fHMCChi2)         delete fHMCChi2;
+  if (fHMCSigDCARPhi)   delete fHMCSigDCARPhi;
+  if (fHMCSigDCAZ)      delete fHMCSigDCAZ;
+  if (fHMCSigPt)        delete fHMCSigPt;
+  if (fHMCNCl)          delete fHMCNCl;
+  if (fHMCFakePatt)     delete fHMCFakePatt;
+}
+
+
+//____________________________________________________________________________
+void KMCTrackSummary::Add(const KMCTrackSummary* src, double scl)
+{
+  if (fHMCChi2)         fHMCChi2->Add(src->fHMCChi2,scl);
+  if (fHMCSigDCARPhi)   fHMCSigDCARPhi->Add(src->fHMCSigDCARPhi,scl);
+  if (fHMCSigDCAZ)      fHMCSigDCAZ->Add(src->fHMCSigDCAZ,scl);
+  if (fHMCSigPt)        fHMCSigPt->Add(src->fHMCSigPt,scl);
+  if (fHMCNCl)          fHMCNCl->Add(src->fHMCNCl,scl);
+  if (fHMCFakePatt)     fHMCFakePatt->Add(src->fHMCFakePatt,scl);
+  fCountAcc += src->fCountAcc;
+  fUpdCalls += src->fUpdCalls;
+}
+
+//____________________________________________________________________________
+void KMCTrackSummary::PrependTNamed(TNamed* obj, const char* nm, const char* tit)
+{
+  // prepend  name, title by this prefix
+  TString name = obj->GetName(),title = obj->GetTitle();
+  name.Prepend(nm); title.Prepend(tit);
+  obj->SetNameTitle(name.Data(),title.Data());
+  //
+}
+  
+//____________________________________________________________________________
+void KMCTrackSummary::SetNamePrefix(const char* pref)
+{
+  // prepend all names by this prefix
+  TString nmT,nmP = pref;
+  if (nmP.IsNull()) return;
+  nmP = Form("%s_",pref);
+  nmT = Form("%s ",pref);
+  PrependTNamed(this, nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCChi2,       nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCSigDCARPhi, nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCSigDCAZ,    nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCSigPt,      nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCNCl,        nmP.Data(), nmT.Data());
+  PrependTNamed(fHMCFakePatt,   nmP.Data(), nmT.Data());
+  //  
+}
+
+//____________________________________________________________________________
+Bool_t KMCTrackSummary::CheckTrack(KMCProbe* trc)
+{
+  // check if the track satisfies to selection conditions
+  fCountTot++;
+  if (!trc) return kFALSE;
+  if (OutOfRange(trc->GetNITSHits(), fMinMaxClITS)) return kFALSE;
+  if (OutOfRange(trc->GetNFakeITSHits(), fMinMaxClITSFake)) return kFALSE;
+  if (OutOfRange(trc->GetNITSHits()-trc->GetNFakeITSHits(), fMinMaxClITSCorr)) return kFALSE;
+  //
+  // check layer patterns if requested
+  UInt_t patt  = trc->GetHitsPatt();
+  UInt_t pattF = trc->GetFakesPatt();
+  UInt_t pattC = patt&(~pattF);    // correct hits
+  // is there at least one hit in each of requested layer groups?
+  for (int ip=fPattITS.GetSize();ip--;)     if (!CheckPattern(patt,fPattITS[ip])) return kFALSE;
+  // is there at least one fake in any of requested layer groups?
+  for (int ip=fPattITSFakeExcl.GetSize();ip--;) if (CheckPattern(pattF,fPattITSFakeExcl[ip])) return kFALSE;
+  // is there at least one correct hit in each of requested layer groups?
+  for (int ip=fPattITSCorr.GetSize();ip--;) if (!CheckPattern(pattC,fPattITSCorr[ip])) return kFALSE;
+  //
+  fCountAcc++;
+  return kTRUE;
+}
+
+//____________________________________________________________________________
+void KMCTrackSummary::AddTrack(KMCProbe* trc)
+{
+  // fill track info
+  if (!CheckTrack(trc)) return;
+  //
+  fHMCChi2->Fill(trc->GetNormChi2(kFALSE));
+  fHMCSigDCARPhi->Fill(trc->GetY());
+  fHMCSigDCAZ->Fill(trc->GetZ());
+  if (fRefProbe.Pt()>0) fHMCSigPt->Fill( trc->Pt()/fRefProbe.Pt()-1.);
+  //  printf("Pts: %.3f %.3f -> %.3f\n",trc->Pt(),fRefProbe.Pt(),trc->Pt()/fRefProbe.Pt()-1.);
+  //  trc->Print("l");
+  //  fRefProbe.Print("l");
+  fHMCNCl->Fill(trc->GetNITSHits(),trc->GetNFakeITSHits());
+  for (int i=trc->GetNITSLayers();i--;) if (trc->IsHitFake(i)) fHMCFakePatt->Fill(i);
+  //
+}
+
+//____________________________________________________________________________
+UInt_t KMCTrackSummary::Bits(Bool_t l0, Bool_t l1, Bool_t l2, Bool_t l3, Bool_t l4, Bool_t l5, Bool_t l6, Bool_t l7,Bool_t  l8, Bool_t l9,
+                         Bool_t l10,Bool_t l11,Bool_t l12,Bool_t l13,Bool_t l14,Bool_t l15,Bool_t l16,Bool_t l17,Bool_t l18,Bool_t l19,
+                         Bool_t l20,Bool_t l21,Bool_t l22,Bool_t l23,Bool_t l24,Bool_t l25,Bool_t l26,Bool_t l27,Bool_t l28,Bool_t l29,
+                         Bool_t l30,Bool_t l31)
+{
+  // create corresponding bit pattern
+  UInt_t patt = 0;
+  if (l0 ) patt |= (0x1<<0);    if (l1 ) patt |= (0x1<<1);   if (l2 ) patt |= (0x1<<2);
+  if (l3 ) patt |= (0x1<<3);    if (l4 ) patt |= (0x1<<4);   if (l5 ) patt |= (0x1<<5);
+  if (l6 ) patt |= (0x1<<6);    if (l7 ) patt |= (0x1<<7);   if (l8 ) patt |= (0x1<<8);
+  if (l9 ) patt |= (0x1<<9);    if (l10) patt |= (0x1<<10);  if (l11) patt |= (0x1<<11);
+  if (l12) patt |= (0x1<<12);   if (l13) patt |= (0x1<<13);  if (l14) patt |= (0x1<<14);
+  if (l15) patt |= (0x1<<15);   if (l16) patt |= (0x1<<16);  if (l17) patt |= (0x1<<17);
+  if (l18) patt |= (0x1<<18);   if (l19) patt |= (0x1<<19);  if (l20) patt |= (0x1<<20);
+  if (l21) patt |= (0x1<<21);   if (l22) patt |= (0x1<<22);  if (l23) patt |= (0x1<<23);
+  if (l24) patt |= (0x1<<24);   if (l25) patt |= (0x1<<25);  if (l26) patt |= (0x1<<26);
+  if (l27) patt |= (0x1<<27);   if (l28) patt |= (0x1<<28);  if (l29) patt |= (0x1<<29);
+  if (l30) patt |= (0x1<<30);   if (l31) patt |= (0x1<<31);   
+  return patt;
+}
+
+//__________________________________________________________________________
+void KMCTrackSummary::Print(Option_t* ) const
+{
+  printf("%s: summary for track M=%5.3f pT: %6.3f eta: %.2f\n", GetName(),
+        fRefProbe.GetMass(),fRefProbe.Pt(), fRefProbe.Eta());
+  printf("Cuts on NCl ITS: Tot: %2d - %2d Fake: %2d - %2d Corr: %2d - %2d\n",
+        fMinMaxClITS[0],fMinMaxClITS[1], 
+        fMinMaxClITSFake[0],fMinMaxClITSFake[1],
+        fMinMaxClITSCorr[0],fMinMaxClITSCorr[1]);
+  //
+  int nlr = fNITSLayers;
+  if (fPattITS.GetSize()) {
+    printf("Require at least 1 hit in groups: ");
+    printf("Hits obligatory in groups: ");
+    for (int i=fPattITS.GetSize();i--;) {
+      UInt_t pat = (UInt_t)fPattITS[i];
+      printf("[");
+      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);
+      printf("] ");
+    }
+    printf("\n");
+  }
+  //
+  if (fPattITSFakeExcl.GetSize()) {
+    printf("Fake hit forbidden in groups    : ");
+    for (int i=fPattITSFakeExcl.GetSize();i--;) {
+      UInt_t pat = (UInt_t)fPattITSFakeExcl[i];
+      printf("[");
+      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);
+      printf("] ");
+    }
+    printf("\n");
+  }
+  //
+  if (fPattITSCorr.GetSize()) {
+    printf("Correct hit obligatory in groups: ");
+    for (int i=fPattITSCorr.GetSize();i--;) {
+      UInt_t pat = (UInt_t)fPattITSCorr[i];
+      printf("[");
+      for (int j=0;j<nlr;j++) if (pat&(0x1<<j)) printf("%d ",j);
+      printf("] ");
+    }
+    printf("\n");
+  }
+  //  
+  printf("Entries: Tot: %.4e Acc: %.4e -> Eff: %.4f+-%.4f %.2e KMC updates\n",fCountTot,fCountAcc,GetEff(),GetEffErr(),GetUpdCalls());
+}
+