Exemple #1
0
// analisi
Bool_t CheckSingle(const char* esdFileName,Bool_t kGRID){
  //inizializzo a zero ncluster (di tree T)
  //for (int ifc=0;ifc<10000;ifc++) ncluster[ifc]=0;
  
  // check the content of the ESD
  
  AliPIDResponse *pidr = new AliPIDResponse();
  
  // open the ESD file
  TFile* esdFile = TFile::Open(esdFileName);
  if (!esdFile || !esdFile->IsOpen()){
    Error("CheckESD", "opening ESD file %s failed", esdFileName);
    return kFALSE;
  }
  
  TString mctrkref(esdFileName);
  mctrkref.ReplaceAll("AliESDs.root","TrackRefs.root");
  TString fgal(esdFileName);
  fgal.ReplaceAll("AliESDs.root","galice.root");
  
  if(kGRID){
    fgal.Insert(0,"alien://");
    mctrkref.Insert(0,"alien://");
  }
  
  TTree *trkref;
  
  printf("ESD = %s\n",esdFileName);
  
  TFile *ftrkref; 
  if(isMC) ftrkref = TFile::Open(mctrkref.Data());
  
  AliHeader *h = new AliHeader();
  
  TFile *fgalice;
  if(isMC) fgalice = TFile::Open(fgal.Data());
  TTree *tgalice;
  if(isMC){
    tgalice = (TTree *) fgalice->Get("TE");
    tgalice->SetBranchAddress("Header",&h);
  }
  
  AliRunLoader* runLoader = NULL;
  
  AliRun *gAlice;
  if(isMC) runLoader = AliRunLoader::Open(fgal.Data());
  if(runLoader){
    runLoader->LoadgAlice();
    gAlice = runLoader->GetAliRun();
    if (!gAlice) {
      Error("CheckESD", "no galice object found");
      return kFALSE;
    }
    runLoader->LoadKinematics();
    runLoader->LoadHeader();
  }
  
  AliESDEvent * esd = new AliESDEvent;
  //  printf("esd object = %x\n",esd);
  TTree* tree = (TTree*) esdFile->Get("esdTree");
  if (!tree){
    Error("CheckESD", "no ESD tree found");
    return kFALSE;
  }
  esd->ReadFromTree(tree); // crea link tra esd e tree
  
  TClonesArray* tofcl;  // array dinamico
  TClonesArray* tofhit;
  TClonesArray* tofmatch;
  
  Int_t nev = tree->GetEntries(); //ogni entries evento
  Float_t mag;
  
  printf("nev = %i\n",nev);
  
  //azzero il contatore delle tracce del TTree T
  //ntracks=0;
  AliStack* stack=NULL;
  
  Int_t trkassociation[1000000];
  
  for(Int_t ie=0;ie < nev;ie++){
    if(runLoader){
      runLoader->GetEvent(ie);
      
      // select simulated primary particles, V0s and cascades
      stack = runLoader->Stack();
    }
    
    if(isMC) trkref = (TTree *) ftrkref->Get(Form("Event%i/TreeTR",ie));
    tree->GetEvent(ie);
    if(isMC) tgalice->GetEvent(ie);
    
    if(isMC) interactiontime = h->GenEventHeader()->InteractionTime()*1E+12;
    
    mag = esd->GetMagneticField();
    
    AliTOFHeader *tofh = esd->GetTOFHeader();
    ntofcl = tofh->GetNumberOfTOFclusters();
    
    esd->ConnectTracks(); // Deve essere sempre chiamato dopo aver letto l'evento (non troverebbe l'ESDevent). Scrivo in tutte le tracce l origine dell evento così poi da arrivare ovunque(tipo al cluster e al tempo quindi).
    
    
    //Riempio variabile del tree "T"
    //nevento=ie;
    
    if(! esd->GetVertex()){
      esd->ResetStdContent();
      continue;// una volta fatto il connect manda un flag ; siccome qua c'era un continue(non si arriva in fondo al ciclo) bisogna resettarlo altrimenti lo trova già attivo.
    }
    
    tofcl = esd->GetESDTOFClusters(); // AliESDTOFCluster *cltof = tofcl->At(i);
    if(tofcl->GetEntries() == 0){
      esd->ResetStdContent();
      continue;
    }
    tofhit = esd->GetESDTOFHits(); // AliESDTOFHit *hittof = tofhit->At(i);
    tofmatch = esd->GetESDTOFMatches(); // AliESDTOFHit *mathctof = tofmatch->At(i);
    
    // loop over tracks
    
    pidr->SetTOFResponse(esd,AliPIDResponse::kTOF_T0); //per recuperare lo start time ("esd", "tipo start time"), tipo cioè o il TOF stesso o il T0 o il best, ovvero la combinazione dei 2
    
    Int_t ntrk = esd->GetNumberOfTracks();
    
    //printf("%i) TPC tracks = %i -- TOF cluster = %i - TOF hit = %i -- matchable info = %i\n",ie,ntrk,tofcl->GetEntries(),tofhit->GetEntries(),tofmatch->GetEntries());
    
    Double_t time[AliPID::kSPECIESC];
    
    
    if(isMC && stack){// create association trackref
      printf("nMC track = %i\n",stack->GetNtrack());
      for(Int_t ist=0;ist < stack->GetNtrack();ist++){
	trkassociation[ist]=-1;
      }
      for(Int_t iref=0;iref < trkref->GetEntries();iref++){
	trkref->GetEvent(iref);
	Int_t trkreference = trkref->GetLeaf("TrackReferences.fTrack")->GetValue();
	if(trkreference > -1 && trkreference < 1000000){
	  trkassociation[trkreference] = iref;
	}
      }
    }
    
    for (Int_t iTrack = 0; iTrack < ntrk; iTrack++){
      AliESDtrack* track = esd->GetTrack(iTrack);
      
      // select tracks of selected particles
      if ((track->GetStatus() & AliESDtrack::kITSrefit) == 0) continue;//almeno un hit nell ITS
      if (track->GetConstrainedChi2() > 4) continue; //se brutto X^2
      if ((track->GetStatus() & AliESDtrack::kTOFout) == 0) continue; //se traccia matchata con tof
      if(track->GetNumberOfTPCClusters() < 70) continue;
      Float_t p =track->P();
      
      itrig = 0;
      timetrig = 0;
      
      if(p > 0.9 && p < 1.1){
 	track->GetIntegratedTimes(time);
	
	itrig = iTrack;
	timetrig = track->GetTOFsignal() - time[2];
	iTrack = ntrk;
      }
    }
    
    printf("real loop, ntrk = %i\n",ntrk);
  
    for (Int_t iTrack = 0; iTrack < ntrk; iTrack++){
      AliESDtrack* track = esd->GetTrack(iTrack);
      
      // select tracks of selected particles
      if ((track->GetStatus() & AliESDtrack::kITSrefit) == 0) continue;//almeno un hit nell ITS
      if (track->GetConstrainedChi2() > 4) continue; //se brutto X^2
      
      //if ((track->GetStatus() & AliESDtrack::kTOFout) == 0) continue; //se traccia matchata con tof
      if(track->GetNumberOfTPCClusters() < 70) continue;

      TOFout = (track->GetStatus() & AliESDtrack::kTOFout) > 0;

      track->GetIntegratedTimes(time);
      
      Float_t dx = track->GetTOFsignalDx(); //leggo i residui tra traccia e canale tof acceso
      Float_t dz = track->GetTOFsignalDz();
      
      mism = 0;
      
      dedx = track->GetTPCsignal();
      
      Int_t label = TMath::Abs(track->GetLabel());
      if(stack){
	TParticle *part=stack->Particle(label);
	pdg = part->GetPdgCode();
      }
      
      Int_t TOFlabel[3];
      track->GetTOFLabel(TOFlabel);
      
      //  printf("%i %i %i %i\n",label,TOFlabel[0],TOFlabel[1],TOFlabel[2]);
      
      ChannelTOF[0] = track->GetTOFCalChannel();
      //      printf("geant time = %f\n",gtime);
      //getchar();
      // if(TMath::Abs(dx) > 1.25 || TMath::Abs(dz) > 1.75) continue; // is inside the pad
      
      //riempio il numro di cludter e impulso trasverso per traccia del TTree T
      ncluster=track->GetNTOFclusters();
      impulso_trasv=track->Pt();
      impulso=track->P();
      
      StartTime = pidr->GetTOFResponse().GetStartTime(track->P());
      StartTimeRes = pidr->GetTOFResponse().GetStartTimeRes(track->P());
      
      if(track->Pt() > 0.9 && track->Pt() < 1.5){  //impulso non troppo alto per separazione tra particelle
	Float_t dt = track->GetTOFsignal() - time[2] - pidr->GetTOFResponse().GetStartTime(track->P());//tempo TOF(è lo stesso di Gettime, solo che lo prendo dale tracce)(già calibrato) -ip del PI (posizione 0 e, posizione 1 mu, pos 2 PI, pos 3 K,pos 4 p) -start time
	Float_t dtKa = track->GetTOFsignal() - time[3] - pidr->GetTOFResponse().GetStartTime(track->P());
	Float_t dtPr = track->GetTOFsignal() - time[4] - pidr->GetTOFResponse().GetStartTime(track->P());
	hdt->Fill(dt);
	hdtKa->Fill(dtKa);
	hdtPr->Fill(dtPr);
      }
      
      charge = track->Charge();
      phi = track->Phi();
      eta = track->Eta();

      GetPositionAtTOF(track,mag,coord);
      phiExt = TMath::ATan2(coord[1],coord[0]);
      etaExt =  -TMath::Log(TMath::Tan(0.5*TMath::ATan2(sqrt(coord[0]*coord[0]+coord[1]*coord[1]),coord[2])));

      for (int i=0;i<(track->GetNTOFclusters());i++){
	int idummy=track->GetTOFclusterArray()[i];
        
	AliESDTOFCluster *cl = (AliESDTOFCluster *) tofcl->At(idummy);
        
	tempo[i]=cl->GetTime();
	tot[i]=cl->GetTOT();
        
	ChannelTOF[i]=cl->GetTOFchannel();
		
	if(i==0){
	  GetResolutionAtTOF(track,mag,ChannelTOF[i],res);
	}
	
	for(int im=cl->GetNMatchableTracks();im--;){ //o così o da n-1 a 0 //for(int im=cl->GetNMatchableTracks();im>0;im--) non andava bene perchè non prendeva mai lo 0  
	  
	  //	    if(track->GetNTOFclusters()==2) printf("-- %i) %f %f\n",im,cl->GetLength(im),cl->GetIntegratedTime(2,im));
	  
	  if(cl->GetTrackIndex(im) == track->GetID()){
	    exp_time_el[i] = cl->GetIntegratedTime(0,im); // pi = 2
	    exp_time_mu[i] = cl->GetIntegratedTime(1,im); // pi = 2
	    exp_time_pi[i] = cl->GetIntegratedTime(2,im); // pi = 2
	    exp_time_ka[i] = cl->GetIntegratedTime(3,im); // pi = 2
	    exp_time_pr[i] = cl->GetIntegratedTime(4,im); // pi = 2
	    L[i] = cl->GetLength(im);
	    //		  if(track->GetNTOFclusters()==2)printf("%i) %f %f\n",i,L[i],exp_time_pi[i]);
	    DeltaX[i]=cl->GetDx(im); // mettendolo dentro questo if dovrei prendere i residui di una stessa traccia
	    DeltaZ[i]=cl->GetDz(im);
	  }
	}
      }
         
      //ReMatch();
      
      Int_t jref=0;
      if(isMC){
	if(TOFlabel[0] > -1 && TOFlabel[0] < 1000000){
	  trkref->GetEvent(trkassociation[TOFlabel[0]]);
	  if(TOFlabel[0] == trkref->GetLeaf("TrackReferences.fTrack")->GetValue()){
	    //  printf("trk -> %i (%i)\n",trkref->GetLeaf("TrackReferences.fTrack")->GetValue(),trkref->GetLeaf("TrackReferences.fTrack")->GetValue(jref));	
	    while(jref > -1 && trkref->GetLeaf("TrackReferences.fTrack")->GetValue(jref) != 0){
	      //printf("det = %i\n",trkref->GetLeaf("TrackReferences.fDetectorId")->GetValue(jref));
	      if(trkref->GetLeaf("TrackReferences.fDetectorId")->GetValue(jref) == 4){
		gtime=trkref->GetLeaf("TrackReferences.fTime")->GetValue(jref)*1E+12;
		xgl = trkref->GetLeaf("TrackReferences.fX")->GetValue(jref);
		ygl = trkref->GetLeaf("TrackReferences.fY")->GetValue(jref);
		zgl = trkref->GetLeaf("TrackReferences.fZ")->GetValue(jref);
		MakeTrueRes();
		jref =  100;
	      }
	      jref++;
	    }
	  }
	}
      }
      
      
      if(TMath::Abs(label) != TOFlabel[0] && stack){
	mism=2;
	
	while(TOFlabel[0] != -1 && TOFlabel[0] != label){
	  TOFlabel[0] = stack->Particle(TOFlabel[0])->GetMother(0);
	}
	
	if(label == TOFlabel[0])
	  mism=1;	
	
      }
      
      //AddDelay();
      T->Fill(); //cout<<"riempio il tree  "<<endl; //Riempio tree "T"
    
      
      
      //incremento il contatore delle tracce del TTree T matchate e che superano i tagli
      //ntracks++;
      
    }//end of for(tracks)
      
      
    
    esd->ResetStdContent();
    
    
    
  } //end of for(events)

  if(runLoader){
    runLoader->UnloadHeader();
    runLoader->UnloadKinematics();
    delete runLoader;
  }
  
  esdFile->Close();
  if(isMC) ftrkref->Close();
  if(isMC) fgalice->Close();
}
Exemple #2
0
Bool_t CheckESD(const char* gAliceFileName = "galice.root", 
		const char* esdFileName = "AliESDs.root")
{
// check the content of the ESD
 
  // check values
  Int_t    checkNGenLow = 1;

  Double_t checkEffLow = 0.5;
  Double_t checkEffSigma = 3;
  Double_t checkFakeHigh = 0.5;
  Double_t checkFakeSigma = 3;

  Double_t checkResPtInvHigh = 5;
  Double_t checkResPtInvSigma = 3;
  Double_t checkResPhiHigh = 10;
  Double_t checkResPhiSigma = 3;
  Double_t checkResThetaHigh = 10;
  Double_t checkResThetaSigma = 3;

  Double_t checkPIDEffLow = 0.5;
  Double_t checkPIDEffSigma = 3;
  Double_t checkResTOFHigh = 500;
  Double_t checkResTOFSigma = 3;

  Double_t checkPHOSNLow = 5;
  Double_t checkPHOSEnergyLow = 0.3;
  Double_t checkPHOSEnergyHigh = 1.0;
  Double_t checkEMCALNLow = 50;
  Double_t checkEMCALEnergyLow = 0.05;
  Double_t checkEMCALEnergyHigh = 1.0;

  Double_t checkMUONNLow = 1;
  Double_t checkMUONPtLow = 0.5;
  Double_t checkMUONPtHigh = 10.;

  Double_t cutPtV0 = 0.3;
  Double_t checkV0EffLow = 0.02;
  Double_t checkV0EffSigma = 3;
  Double_t cutPtCascade = 0.5;
  Double_t checkCascadeEffLow = 0.01;
  Double_t checkCascadeEffSigma = 3;

  // open run loader and load gAlice, kinematics and header
  AliRunLoader* runLoader = AliRunLoader::Open(gAliceFileName);
  if (!runLoader) {
    Error("CheckESD", "getting run loader from file %s failed", 
	    gAliceFileName);
    return kFALSE;
  }
  runLoader->LoadgAlice();
  gAlice = runLoader->GetAliRun();
  if (!gAlice) {
    Error("CheckESD", "no galice object found");
    return kFALSE;
  }
  runLoader->LoadKinematics();
  runLoader->LoadHeader();

  // open the ESD file
  TFile* esdFile = TFile::Open(esdFileName);
  if (!esdFile || !esdFile->IsOpen()) {
    Error("CheckESD", "opening ESD file %s failed", esdFileName);
    return kFALSE;
  }
  AliESDEvent * esd = new AliESDEvent;
  TTree* tree = (TTree*) esdFile->Get("esdTree");
  if (!tree) {
    Error("CheckESD", "no ESD tree found");
    return kFALSE;
  }
  esd->ReadFromTree(tree);

  // efficiency and resolution histograms
  Int_t nBinsPt = 15;
  Float_t minPt = 0.1;
  Float_t maxPt = 3.1;
  TH1F* hGen = CreateHisto("hGen", "generated tracks", 
			   nBinsPt, minPt, maxPt, "p_{t} [GeV/c]", "N");
  TH1F* hRec = CreateHisto("hRec", "reconstructed tracks", 
			   nBinsPt, minPt, maxPt, "p_{t} [GeV/c]", "N");
  Int_t nGen = 0;
  Int_t nRec = 0;
  Int_t nFake = 0;

  TH1F* hResPtInv = CreateHisto("hResPtInv", "", 100, -10, 10, 
           "(p_{t,rec}^{-1}-p_{t,sim}^{-1}) / p_{t,sim}^{-1} [%]", "N");
  TH1F* hResPhi = CreateHisto("hResPhi", "", 100, -20, 20, 
			      "#phi_{rec}-#phi_{sim} [mrad]", "N");
  TH1F* hResTheta = CreateHisto("hResTheta", "", 100, -20, 20, 
				"#theta_{rec}-#theta_{sim} [mrad]", "N");

  // PID
  Int_t partCode[AliPID::kSPECIES] = 
    {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton};
  const char* partName[AliPID::kSPECIES+1] = 
    {"electron", "muon", "pion", "kaon", "proton", "other"};
  Double_t partFrac[AliPID::kSPECIES] = 
    {0.01, 0.01, 0.85, 0.10, 0.05};
  Int_t identified[AliPID::kSPECIES+1][AliPID::kSPECIES];
  for (Int_t iGen = 0; iGen < AliPID::kSPECIES+1; iGen++) {
    for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) {
      identified[iGen][iRec] = 0;
    }
  }
  Int_t nIdentified = 0;

  // dE/dx and TOF
  TH2F* hDEdxRight = new TH2F("hDEdxRight", "", 300, 0, 3, 100, 0, 400);
  hDEdxRight->SetStats(kFALSE);
  hDEdxRight->GetXaxis()->SetTitle("p [GeV/c]");
  hDEdxRight->GetYaxis()->SetTitle("dE/dx_{TPC}");
  hDEdxRight->SetMarkerStyle(kFullCircle);
  hDEdxRight->SetMarkerSize(0.4);
  TH2F* hDEdxWrong = new TH2F("hDEdxWrong", "", 300, 0, 3, 100, 0, 400);
  hDEdxWrong->SetStats(kFALSE);
  hDEdxWrong->GetXaxis()->SetTitle("p [GeV/c]");
  hDEdxWrong->GetYaxis()->SetTitle("dE/dx_{TPC}");
  hDEdxWrong->SetMarkerStyle(kFullCircle);
  hDEdxWrong->SetMarkerSize(0.4);
  hDEdxWrong->SetMarkerColor(kRed);
  TH1F* hResTOFRight = CreateHisto("hResTOFRight", "", 100, -1000, 1000, 
				   "t_{TOF}-t_{track} [ps]", "N");
  TH1F* hResTOFWrong = CreateHisto("hResTOFWrong", "", 100, -1000, 1000, 
				   "t_{TOF}-t_{track} [ps]", "N");
  hResTOFWrong->SetLineColor(kRed);

  // calorimeters
  TH1F* hEPHOS = CreateHisto("hEPHOS", "PHOS", 100, 0, 50, "E [GeV]", "N");
  TH1F* hEEMCAL = CreateHisto("hEEMCAL", "EMCAL", 100, 0, 50, "E [GeV]", "N");

  // muons
  TH1F* hPtMUON = CreateHisto("hPtMUON", "MUON", 100, 0, 20, 
			      "p_{t} [GeV/c]", "N");

  // V0s and cascades
  TH1F* hMassK0 = CreateHisto("hMassK0", "K^{0}", 100, 0.4, 0.6, 
			      "M(#pi^{+}#pi^{-}) [GeV/c^{2}]", "N");
  TH1F* hMassLambda = CreateHisto("hMassLambda", "#Lambda", 100, 1.0, 1.2, 
				  "M(p#pi^{-}) [GeV/c^{2}]", "N");
  TH1F* hMassLambdaBar = CreateHisto("hMassLambdaBar", "#bar{#Lambda}", 
				     100, 1.0, 1.2, 
				     "M(#bar{p}#pi^{+}) [GeV/c^{2}]", "N");
  Int_t nGenV0s = 0;
  Int_t nRecV0s = 0;
  TH1F* hMassXi = CreateHisto("hMassXi", "#Xi", 100, 1.2, 1.5, 
			      "M(#Lambda#pi) [GeV/c^{2}]", "N");
  TH1F* hMassOmega = CreateHisto("hMassOmega", "#Omega", 100, 1.5, 1.8, 
				 "M(#LambdaK) [GeV/c^{2}]", "N");
  Int_t nGenCascades = 0;
  Int_t nRecCascades = 0;

  // loop over events
  for (Int_t iEvent = 0; iEvent < runLoader->GetNumberOfEvents(); iEvent++) {
    runLoader->GetEvent(iEvent);

    // select simulated primary particles, V0s and cascades
    AliStack* stack = runLoader->Stack();
    Int_t nParticles = stack->GetNtrack();
    TArrayF vertex(3);
    runLoader->GetHeader()->GenEventHeader()->PrimaryVertex(vertex);
    TObjArray selParticles;
    TObjArray selV0s;
    TObjArray selCascades;
    for (Int_t iParticle = 0; iParticle < nParticles; iParticle++) {
      TParticle* particle = stack->Particle(iParticle);
      if (!particle) continue;
      if (particle->Pt() < 0.001) continue;
      if (TMath::Abs(particle->Eta()) > 0.9) continue;
      TVector3 dVertex(particle->Vx() - vertex[0], 
		       particle->Vy() - vertex[1],
		       particle->Vz() - vertex[2]);
      if (dVertex.Mag() > 0.0001) continue;

      switch (TMath::Abs(particle->GetPdgCode())) {
      case kElectron:
      case kMuonMinus:
      case kPiPlus:
      case kKPlus:
      case kProton: {
	if (particle->Pt() > minPt) {
	  selParticles.Add(particle);
	  nGen++;
	  hGen->Fill(particle->Pt());
	}
	break;
      }
      case kK0Short:
      case kLambda0: {
	if (particle->Pt() > cutPtV0) {
	  nGenV0s++;
	  selV0s.Add(particle);
	}
	break;
      }
      case kXiMinus:
      case kOmegaMinus: {
	if (particle->Pt() > cutPtCascade) {
	  nGenCascades++;
	  selCascades.Add(particle);
	}
	break;
      }
      default: break;
      }
    }

    // get the event summary data
    tree->GetEvent(iEvent);
    if (!esd) {
      Error("CheckESD", "no ESD object found for event %d", iEvent);
      return kFALSE;
    }

    // loop over tracks
    for (Int_t iTrack = 0; iTrack < esd->GetNumberOfTracks(); iTrack++) {
      AliESDtrack* track = esd->GetTrack(iTrack);

      // select tracks of selected particles
      Int_t label = TMath::Abs(track->GetLabel());
      if (label > stack->GetNtrack()) continue;     // background
      TParticle* particle = stack->Particle(label);
      if (!selParticles.Contains(particle)) continue;
      if ((track->GetStatus() & AliESDtrack::kITSrefit) == 0) continue;
      if (track->GetConstrainedChi2() > 1e9) continue;
      selParticles.Remove(particle);   // don't count multiple tracks

      nRec++;
      hRec->Fill(particle->Pt());
      if (track->GetLabel() < 0) nFake++;

      // resolutions
      hResPtInv->Fill(100. * (TMath::Abs(track->GetSigned1Pt()) - 1./particle->Pt()) * 
		      particle->Pt());
      hResPhi->Fill(1000. * (track->Phi() - particle->Phi()));
      hResTheta->Fill(1000. * (track->Theta() - particle->Theta()));

      // PID
      if ((track->GetStatus() & AliESDtrack::kESDpid) == 0) continue;
      Int_t iGen = 5;
      for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
	if (TMath::Abs(particle->GetPdgCode()) == partCode[i]) iGen = i;
      }
      Double_t probability[AliPID::kSPECIES];
      track->GetESDpid(probability);
      Double_t pMax = 0;
      Int_t iRec = 0;
      for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
	probability[i] *= partFrac[i];
	if (probability[i] > pMax) {
	  pMax = probability[i];
	  iRec = i;
	}
      }
      identified[iGen][iRec]++;
      if (iGen == iRec) nIdentified++;

      // dE/dx and TOF
      Double_t time[AliPID::kSPECIES];
      track->GetIntegratedTimes(time);
      if (iGen == iRec) {
	hDEdxRight->Fill(particle->P(), track->GetTPCsignal());
        if ((track->GetStatus() & AliESDtrack::kTOFpid) != 0) {
	  hResTOFRight->Fill(track->GetTOFsignal() - time[iRec]);
	}
      } else {
	hDEdxWrong->Fill(particle->P(), track->GetTPCsignal());
        if ((track->GetStatus() & AliESDtrack::kTOFpid) != 0) {
	  hResTOFWrong->Fill(track->GetTOFsignal() - time[iRec]);
	}
      }
    }

    // loop over muon tracks
    {
    for (Int_t iTrack = 0; iTrack < esd->GetNumberOfMuonTracks(); iTrack++) {
      AliESDMuonTrack* muonTrack = esd->GetMuonTrack(iTrack);
      Double_t ptInv = TMath::Abs(muonTrack->GetInverseBendingMomentum());
      if (ptInv > 0.001) {
	hPtMUON->Fill(1./ptInv);
      }
    }
    }

    // loop over V0s
    for (Int_t iV0 = 0; iV0 < esd->GetNumberOfV0s(); iV0++) {
      AliESDv0* v0 = esd->GetV0(iV0);
      if (v0->GetOnFlyStatus()) continue;
      v0->ChangeMassHypothesis(kK0Short);
      hMassK0->Fill(v0->GetEffMass());
      v0->ChangeMassHypothesis(kLambda0);
      hMassLambda->Fill(v0->GetEffMass());
      v0->ChangeMassHypothesis(kLambda0Bar);
      hMassLambdaBar->Fill(v0->GetEffMass());

      Int_t negLabel = TMath::Abs(esd->GetTrack(v0->GetNindex())->GetLabel());
      if (negLabel > stack->GetNtrack()) continue;     // background
      Int_t negMother = stack->Particle(negLabel)->GetMother(0);
      if (negMother < 0) continue;
      Int_t posLabel = TMath::Abs(esd->GetTrack(v0->GetPindex())->GetLabel());
      if (posLabel > stack->GetNtrack()) continue;     // background
      Int_t posMother = stack->Particle(posLabel)->GetMother(0);
      if (negMother != posMother) continue;
      TParticle* particle = stack->Particle(negMother);
      if (!selV0s.Contains(particle)) continue;
      selV0s.Remove(particle);
      nRecV0s++;
    }

    // loop over Cascades
    for (Int_t iCascade = 0; iCascade < esd->GetNumberOfCascades(); 
	 iCascade++) {
      AliESDcascade* cascade = esd->GetCascade(iCascade);
      Double_t v0q;
      cascade->ChangeMassHypothesis(v0q,kXiMinus);
      hMassXi->Fill(cascade->GetEffMassXi());
      cascade->ChangeMassHypothesis(v0q,kOmegaMinus);
      hMassOmega->Fill(cascade->GetEffMassXi());

      Int_t negLabel = TMath::Abs(esd->GetTrack(cascade->GetNindex())
				  ->GetLabel());
      if (negLabel > stack->GetNtrack()) continue;     // background
      Int_t negMother = stack->Particle(negLabel)->GetMother(0);
      if (negMother < 0) continue;
      Int_t posLabel = TMath::Abs(esd->GetTrack(cascade->GetPindex())
				  ->GetLabel());
      if (posLabel > stack->GetNtrack()) continue;     // background
      Int_t posMother = stack->Particle(posLabel)->GetMother(0);
      if (negMother != posMother) continue;
      Int_t v0Mother = stack->Particle(negMother)->GetMother(0);
      if (v0Mother < 0) continue;
      Int_t bacLabel = TMath::Abs(esd->GetTrack(cascade->GetBindex())
				  ->GetLabel());
      if (bacLabel > stack->GetNtrack()) continue;     // background
      Int_t bacMother = stack->Particle(bacLabel)->GetMother(0);
      if (v0Mother != bacMother) continue;
      TParticle* particle = stack->Particle(v0Mother);
      if (!selCascades.Contains(particle)) continue;
      selCascades.Remove(particle);
      nRecCascades++;
    }

    // loop over the clusters
    {
      for (Int_t iCluster=0; iCluster<esd->GetNumberOfCaloClusters(); iCluster++) {
	AliESDCaloCluster * clust = esd->GetCaloCluster(iCluster);
	if (clust->IsPHOS()) hEPHOS->Fill(clust->E());
	if (clust->IsEMCAL()) hEEMCAL->Fill(clust->E());
      }
    }

  }

  // perform checks
  if (nGen < checkNGenLow) {
    Warning("CheckESD", "low number of generated particles: %d", Int_t(nGen));
  }

  TH1F* hEff = CreateEffHisto(hGen, hRec);

  Info("CheckESD", "%d out of %d tracks reconstructed including %d "
	 "fake tracks", nRec, nGen, nFake);
  if (nGen > 0) {
    // efficiency
    Double_t eff = nRec*1./nGen;
    Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGen);
    Double_t fake = nFake*1./nGen;
    Double_t fakeError = TMath::Sqrt(fake*(1.-fake) / nGen);
    Info("CheckESD", "eff = (%.1f +- %.1f) %%  fake = (%.1f +- %.1f) %%",
	 100.*eff, 100.*effError, 100.*fake, 100.*fakeError);

    if (eff < checkEffLow - checkEffSigma*effError) {
      Warning("CheckESD", "low efficiency: (%.1f +- %.1f) %%", 
	      100.*eff, 100.*effError);
    }
    if (fake > checkFakeHigh + checkFakeSigma*fakeError) {
      Warning("CheckESD", "high fake: (%.1f +- %.1f) %%", 
	      100.*fake, 100.*fakeError);
    }

    // resolutions
    Double_t res, resError;
    if (FitHisto(hResPtInv, res, resError)) {
      Info("CheckESD", "relative inverse pt resolution = (%.1f +- %.1f) %%",
	   res, resError);
      if (res > checkResPtInvHigh + checkResPtInvSigma*resError) {
	Warning("CheckESD", "bad pt resolution: (%.1f +- %.1f) %%", 
		res, resError);
      }
    }

    if (FitHisto(hResPhi, res, resError)) {
      Info("CheckESD", "phi resolution = (%.1f +- %.1f) mrad", res, resError);
      if (res > checkResPhiHigh + checkResPhiSigma*resError) {
	Warning("CheckESD", "bad phi resolution: (%.1f +- %.1f) mrad", 
		res, resError);
      }
    }

    if (FitHisto(hResTheta, res, resError)) {
      Info("CheckESD", "theta resolution = (%.1f +- %.1f) mrad", 
	   res, resError);
      if (res > checkResThetaHigh + checkResThetaSigma*resError) {
	Warning("CheckESD", "bad theta resolution: (%.1f +- %.1f) mrad", 
		res, resError);
      }
    }

    // PID
    if (nRec > 0) {
      Double_t eff = nIdentified*1./nRec;
      Double_t effError = TMath::Sqrt(eff*(1.-eff) / nRec);
      Info("CheckESD", "PID eff = (%.1f +- %.1f) %%", 
	   100.*eff, 100.*effError);
      if (eff < checkPIDEffLow - checkPIDEffSigma*effError) {
	Warning("CheckESD", "low PID efficiency: (%.1f +- %.1f) %%", 
		100.*eff, 100.*effError);
      }
    }

    printf("%9s:", "gen\\rec");
    for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) {
      printf("%9s", partName[iRec]);
    }
    printf("\n");
    for (Int_t iGen = 0; iGen < AliPID::kSPECIES+1; iGen++) {
      printf("%9s:", partName[iGen]);
      for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) {
	printf("%9d", identified[iGen][iRec]);
      }
      printf("\n");
    }

    if (FitHisto(hResTOFRight, res, resError)) {
      Info("CheckESD", "TOF resolution = (%.1f +- %.1f) ps", res, resError);
      if (res > checkResTOFHigh + checkResTOFSigma*resError) {
	Warning("CheckESD", "bad TOF resolution: (%.1f +- %.1f) ps", 
		res, resError);
      }
    }

    // calorimeters
    if (hEPHOS->Integral() < checkPHOSNLow) {
      Warning("CheckESD", "low number of PHOS particles: %d", 
	      Int_t(hEPHOS->Integral()));
    } else {
      Double_t mean = hEPHOS->GetMean();
      if (mean < checkPHOSEnergyLow) {
	Warning("CheckESD", "low mean PHOS energy: %.1f GeV", mean);
      } else if (mean > checkPHOSEnergyHigh) {
	Warning("CheckESD", "high mean PHOS energy: %.1f GeV", mean);
      }
    }

    if (hEEMCAL->Integral() < checkEMCALNLow) {
      Warning("CheckESD", "low number of EMCAL particles: %d", 
	      Int_t(hEEMCAL->Integral()));
    } else {
      Double_t mean = hEEMCAL->GetMean();
      if (mean < checkEMCALEnergyLow) {
	Warning("CheckESD", "low mean EMCAL energy: %.1f GeV", mean);
      } else if (mean > checkEMCALEnergyHigh) {
	Warning("CheckESD", "high mean EMCAL energy: %.1f GeV", mean);
      }
    }

    // muons
    if (hPtMUON->Integral() < checkMUONNLow) {
      Warning("CheckESD", "low number of MUON particles: %d", 
	      Int_t(hPtMUON->Integral()));
    } else {
      Double_t mean = hPtMUON->GetMean();
      if (mean < checkMUONPtLow) {
	Warning("CheckESD", "low mean MUON pt: %.1f GeV/c", mean);
      } else if (mean > checkMUONPtHigh) {
	Warning("CheckESD", "high mean MUON pt: %.1f GeV/c", mean);
      }
    }

    // V0s
    if (nGenV0s > 0) {
      Double_t eff = nRecV0s*1./nGenV0s;
      Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGenV0s);
      if (effError == 0) effError = checkV0EffLow / TMath::Sqrt(1.*nGenV0s);
      Info("CheckESD", "V0 eff = (%.1f +- %.1f) %%", 
	   100.*eff, 100.*effError);
      if (eff < checkV0EffLow - checkV0EffSigma*effError) {
	Warning("CheckESD", "low V0 efficiency: (%.1f +- %.1f) %%", 
		100.*eff, 100.*effError);
      }
    }

    // Cascades
    if (nGenCascades > 0) {
      Double_t eff = nRecCascades*1./nGenCascades;
      Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGenCascades);
      if (effError == 0) effError = checkV0EffLow / 
			   TMath::Sqrt(1.*nGenCascades);
      Info("CheckESD", "Cascade eff = (%.1f +- %.1f) %%", 
	   100.*eff, 100.*effError);
      if (eff < checkCascadeEffLow - checkCascadeEffSigma*effError) {
	Warning("CheckESD", "low Cascade efficiency: (%.1f +- %.1f) %%", 
		100.*eff, 100.*effError);
      }
    }
  }

  // draw the histograms if not in batch mode
  if (!gROOT->IsBatch()) {
    new TCanvas;
    hEff->DrawCopy();
    new TCanvas;
    hResPtInv->DrawCopy("E");
    new TCanvas;
    hResPhi->DrawCopy("E");
    new TCanvas;
    hResTheta->DrawCopy("E");
    new TCanvas;
    hDEdxRight->DrawCopy();
    hDEdxWrong->DrawCopy("SAME");
    new TCanvas;
    hResTOFRight->DrawCopy("E");
    hResTOFWrong->DrawCopy("SAME");
    new TCanvas;
    hEPHOS->DrawCopy("E");
    new TCanvas;
    hEEMCAL->DrawCopy("E");
    new TCanvas;
    hPtMUON->DrawCopy("E");
    new TCanvas;
    hMassK0->DrawCopy("E");
    new TCanvas;
    hMassLambda->DrawCopy("E");
    new TCanvas;
    hMassLambdaBar->DrawCopy("E");
    new TCanvas;
    hMassXi->DrawCopy("E");
    new TCanvas;
    hMassOmega->DrawCopy("E");
  }

  // write the output histograms to a file
  TFile* outputFile = TFile::Open("check.root", "recreate");
  if (!outputFile || !outputFile->IsOpen()) {
    Error("CheckESD", "opening output file check.root failed");
    return kFALSE;
  }
  hEff->Write();
  hResPtInv->Write();
  hResPhi->Write();
  hResTheta->Write();
  hDEdxRight->Write();
  hDEdxWrong->Write();
  hResTOFRight->Write();
  hResTOFWrong->Write();
  hEPHOS->Write();
  hEEMCAL->Write();
  hPtMUON->Write();
  hMassK0->Write();
  hMassLambda->Write();
  hMassLambdaBar->Write();
  hMassXi->Write();
  hMassOmega->Write();
  outputFile->Close();
  delete outputFile;

  // clean up
  delete hGen;
  delete hRec;
  delete hEff;
  delete hResPtInv;
  delete hResPhi;
  delete hResTheta;
  delete hDEdxRight;
  delete hDEdxWrong;
  delete hResTOFRight;
  delete hResTOFWrong;
  delete hEPHOS;
  delete hEEMCAL;
  delete hPtMUON;
  delete hMassK0;
  delete hMassLambda;
  delete hMassLambdaBar;
  delete hMassXi;
  delete hMassOmega;

  delete esd;
  esdFile->Close();
  delete esdFile;

  runLoader->UnloadHeader();
  runLoader->UnloadKinematics();
  delete runLoader;

  // result of check
  Info("CheckESD", "check of ESD was successfull");
  return kTRUE;
}