]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PWGUD/UPC/AliAnalysisTaskUpcFilterSemiforward.cxx
Added classes for UPC analysis
[u/mrichter/AliRoot.git] / PWGUD / UPC / AliAnalysisTaskUpcFilterSemiforward.cxx
diff --git a/PWGUD/UPC/AliAnalysisTaskUpcFilterSemiforward.cxx b/PWGUD/UPC/AliAnalysisTaskUpcFilterSemiforward.cxx
new file mode 100644 (file)
index 0000000..ee58bc9
--- /dev/null
@@ -0,0 +1,746 @@
+
+//_____________________________________________________________________________
+//    Class for semiforward UPC filter
+//    Author: Jaroslav Adam
+//
+//    Fill structure of AliUPCEvent
+//_____________________________________________________________________________
+
+// c++ headers
+#include <iostream>
+#include <string.h>
+
+// root headers
+#include "TList.h"
+#include "TH1I.h"
+#include "TTree.h"
+#include "TClonesArray.h"
+#include "TParticle.h"
+#include "TObjString.h"
+#include "TFile.h"
+#include "TArrayF.h"
+
+// aliroot headers
+#include "AliAnalysisManager.h"
+#include "AliInputEventHandler.h"
+#include "AliESDEvent.h"
+#include "AliAODEvent.h"
+#include "AliMCEvent.h"
+#include "AliAODVZERO.h"
+#include "AliAODZDC.h"
+#include "AliAODVertex.h"
+#include "AliESDVZERO.h"
+#include "AliESDZDC.h"
+#include "AliESDVertex.h"
+#include "AliAODTrack.h"
+#include "AliMultiplicity.h"
+#include "AliESDtrack.h"
+#include "AliESDMuonTrack.h"
+#include "AliAODMCParticle.h"
+#include "AliMCParticle.h"
+#include "AliTriggerAnalysis.h"
+#include "AliMuonTrackCuts.h"
+#include "AliESDtrackCuts.h"
+#include "AliAODPid.h"
+#include "AliGenEventHeader.h"
+#include "AliAODMCHeader.h"
+
+// my headers
+#include "AliAnalysisTaskUpcFilterSemiforward.h"
+#include "AliUPCTrack.h"
+#include "AliUPCMuonTrack.h"
+#include "AliUPCEvent.h"
+
+ClassImp(AliAnalysisTaskUpcFilterSemiforward);
+
+// task for upc semiforward filter
+// jaroslav.adam@cern.ch
+
+//_____________________________________________________________________________
+AliAnalysisTaskUpcFilterSemiforward::AliAnalysisTaskUpcFilterSemiforward(const char *name)
+ :AliAnalysisTaskSE(name),
+  fIsESD(0), fIsMC(0), fMuonCuts(0x0), fTriggerAna(0x0), fCutsList(0x0),
+  fHistList(0x0), fCounter(0x0), fTriggerCounter(0x0),
+  fUPCEvent(0x0), fUPCTree(0x0)
+{
+
+  // Constructor
+
+  DefineOutput(1, TTree::Class());
+  DefineOutput(2, TList::Class());
+
+}//AliAnalysisTaskUpcFilterSemiforward
+
+//_____________________________________________________________________________
+AliAnalysisTaskUpcFilterSemiforward::~AliAnalysisTaskUpcFilterSemiforward()
+{
+  // destructor
+
+  if(fHistList) {delete fHistList; fHistList = 0x0;}
+  if(fCounter) {delete fCounter; fCounter = 0x0;}
+  if(fTriggerCounter) {delete fTriggerCounter; fTriggerCounter = 0x0;}
+  if(fUPCEvent) {delete fUPCEvent; fUPCEvent = 0x0;}
+  if(fUPCTree) {delete fUPCTree; fUPCTree = 0x0;}
+  if(fMuonCuts) {delete fMuonCuts; fMuonCuts = 0x0;}
+  if(fTriggerAna) {delete fTriggerAna; fTriggerAna = 0x0;}
+  if(fCutsList) {delete[] fCutsList; fCutsList=0x0;}
+
+}//~AliAnalysisTaskUpcFilterSemiforward
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::UserCreateOutputObjects()
+{
+  //muon track cuts
+  fMuonCuts = new AliMuonTrackCuts("StdMuonCuts", "StdMuonCuts");
+  fMuonCuts->SetFilterMask ( AliMuonTrackCuts::kMuPdca );
+  fMuonCuts->Print("mask");
+  fMuonCuts->SetAllowDefaultParams(kTRUE);
+  fMuonCuts->SetPassName("muon_pass2");
+
+  //trigger analysis for SPD FO fired chips in MC
+  fTriggerAna = new AliTriggerAnalysis();
+  fTriggerAna->SetAnalyzeMC( fIsMC );
+
+  //ESD track cuts
+  if( fIsESD ) {
+    fCutsList = new AliESDtrackCuts*[32];
+    for(UInt_t i=0; i<32; i++) fCutsList[i] = 0x0;
+
+    // bits 0 - 10 set in $ALICE_ROOT/ANALYSIS/ESDfilter/macros/AddTaskESDFilter.C
+
+    // Cuts on primary tracks
+    AliESDtrackCuts* esdTrackCutsL = AliESDtrackCuts::GetStandardTPCOnlyTrackCuts();
+    fCutsList[0] = esdTrackCutsL;
+
+    // standard cuts with very loose DCA
+    AliESDtrackCuts* esdTrackCutsH = AliESDtrackCuts::GetStandardITSTPCTrackCuts2011(kFALSE); 
+    esdTrackCutsH->SetMaxDCAToVertexXY(2.4);
+    esdTrackCutsH->SetMaxDCAToVertexZ(3.2);
+    esdTrackCutsH->SetDCAToVertex2D(kTRUE);
+    fCutsList[4] = esdTrackCutsH;
+
+    // standard cuts with tight DCA cut
+    AliESDtrackCuts *esdTrackCutsH2 = AliESDtrackCuts::GetStandardITSTPCTrackCuts2011();
+    fCutsList[5] = esdTrackCutsH2;
+
+    // bits 11 - 31 free
+
+    // selection by Daniele, UPC meeting, 15 July 2014
+    // https://indico.cern.ch/event/330483/contribution/3/material/slides/0.pdf
+
+    AliESDtrackCuts *cuts11 = new AliESDtrackCuts();
+    cuts11->SetMinNClustersTPC(70);
+    cuts11->SetRequireTPCRefit(kTRUE);
+    cuts11->SetRequireITSRefit(kTRUE);
+    cuts11->SetMaxChi2PerClusterTPC(4);
+    cuts11->SetAcceptKinkDaughters(kFALSE);
+    cuts11->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kAny);
+    cuts11->SetMaxDCAToVertexXYPtDep("0.0105+0.0350/pt^1.01");
+    cuts11->SetMaxDCAToVertexZ(2);
+    cuts11->SetDCAToVertex2D(kFALSE);
+    cuts11->SetRequireSigmaToVertex(kFALSE);
+    cuts11->SetMaxChi2PerClusterITS(5.);
+    fCutsList[11] = cuts11;
+
+    AliESDtrackCuts *cuts12 = new AliESDtrackCuts();
+    cuts12->SetMinNClustersTPC(70);
+    cuts12->SetRequireTPCRefit(kTRUE);
+    cuts12->SetRequireITSRefit(kTRUE);
+    cuts12->SetMaxChi2PerClusterTPC(4);
+    cuts12->SetAcceptKinkDaughters(kFALSE);
+    cuts12->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kAny);
+    cuts12->SetMaxDCAToVertexXYPtDep("0.0105+0.0350/pt^1.01");
+    cuts12->SetMaxDCAToVertexZ(2);
+    cuts12->SetDCAToVertex2D(kFALSE);
+    cuts12->SetRequireSigmaToVertex(kFALSE);
+    fCutsList[12] = cuts12;
+
+    // setting in Evgeny's trees
+    AliESDtrackCuts *cuts13 = AliESDtrackCuts::GetStandardITSTPCTrackCuts2011();
+    cuts13->SetMaxChi2TPCConstrainedGlobal(1e+10);
+    fCutsList[13] = cuts13;
+
+  }
+
+  //output histograms
+  fHistList = new TList();
+  fHistList->SetOwner();
+  fCounter = new TH1I("fCounter", "fCounter", 30, 1, 31);
+  fHistList->Add(fCounter);
+  fTriggerCounter = new TH2I("fTriggerCounter", "fTriggerCounter", 3000, 195000, 198000, NTRG+1, 0, NTRG+1);
+  fHistList->Add(fTriggerCounter);
+
+  //output tree
+  fUPCEvent  = new AliUPCEvent();
+  fUPCEvent->SetIsMC( fIsMC );
+  fUPCEvent->SetIsESD( fIsESD );
+
+  TDirectory *pwd = gDirectory;
+  OpenFile(1);
+  fUPCTree = new TTree("fUPCTree", "fUPCTree");
+  pwd->cd();
+  fUPCTree->Branch("fUPCEvent", &fUPCEvent);
+
+  PostData(1, fUPCTree);
+  PostData(2, fHistList);
+
+}//UserCreateOutputObjects
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::NotifyRun()
+{
+
+  //cout<<"AliAnalysisTaskUpcFilterSemiforward::NotifyRun()"<<endl;
+
+  fMuonCuts->SetRun(fInputHandler); // use input handler from AliAnalysisTaskSE
+
+  if( fIsESD ) { ((AliESDEvent*) InputEvent())->InitMagneticField(); }
+
+}//NotifyRun
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::UserExec(Option_t *) 
+{
+
+  //cout<<"#################### Next event ##################"<<endl;
+
+  // input event
+  AliVEvent *vEvent = InputEvent();
+  if(!vEvent) return;
+
+  fUPCEvent->ClearEvent();
+
+  fCounter->Fill( 1 ); // 1 = analyzed events
+
+  // trigger
+  TString trigger = vEvent->GetFiredTriggerClasses();
+  Bool_t trgClasses[NTRG]; // array of fired trigger classes
+  for(Int_t itrg=0; itrg<NTRG; itrg++) trgClasses[itrg] = kFALSE;
+
+  trgClasses[1] = trigger.Contains("CMUP6-B"); // p-Pb FW
+  trgClasses[2] = trigger.Contains("CMUP3-B"); // Pb-p FW
+  trgClasses[3] = trigger.Contains("CMUP8-B"); // Pb-p FW
+
+  trgClasses[4] = trigger.Contains("CMUP7-B"); // p-Pb SFW
+  trgClasses[5] = trigger.Contains("CMUP5-B"); // Pb-p SFW
+  trgClasses[6] = trigger.Contains("CMUP9-B"); // Pb-p SFW
+
+  trgClasses[7] = trigger.Contains("CCUP7-B"); // CEN
+
+  trgClasses[8] = trigger.Contains("CMUP7-ACE");
+  trgClasses[9] = trigger.Contains("CMUP5-ACE");
+  trgClasses[10]= trigger.Contains("CMUP9-ACE");
+
+  Bool_t isTrg = kFALSE;
+  for(Int_t itrg=1; itrg<NTRG; itrg++) {
+    if(!trgClasses[itrg]) continue;
+    //trigger at itrg is fired
+    fUPCEvent->SetTriggerClass( itrg , kTRUE );
+    fTriggerCounter->Fill( vEvent->GetRunNumber() , itrg );
+    isTrg = kTRUE;
+  }
+  if(!isTrg && !fIsMC) {PostData(2, fHistList); return;}
+  //event passed the trigger
+
+  fCounter->Fill( 2 ); // 2 = events after trigger (ESD and AOD)
+
+  // ESD / AOD specific tasks: MC, SPD FO, L0 inputs, SPD tracklets, tracks, ZDC tdc
+  Bool_t stat;
+  if( fIsESD ) stat = RunESD();
+  if(!fIsESD ) stat = RunAOD();
+  if( !stat && !fIsMC ) {PostData(2, fHistList); return;}
+  //event passed ESD / AOD specific selection
+
+  fCounter->Fill( 3 ); // 3 = events after ESD / AOD specific part
+
+  // input data
+  const char *filnam = ((TTree*) GetInputData(0))->GetCurrentFile()->GetName();
+  // reconstruction pass: -1 = unknown, 1 = pass1, 2 = pass2, counter indices: 9 (unknown), 11 (pass1), 12 (pass2)
+  fUPCEvent->SetRecoPass( -1 );
+  if( strstr(filnam,"/pass1/") ) {fUPCEvent->SetRecoPass( 1 ); fCounter->Fill( 11 );}
+  if( strstr(filnam,"/pass2/") ) {fUPCEvent->SetRecoPass( 2 ); fCounter->Fill( 12 );}
+  if( fUPCEvent->GetRecoPass() < 0 ) fCounter->Fill( 9 );
+  fUPCEvent->SetInputFileName( filnam );
+  fUPCEvent->SetEventNumber( ((TTree*) GetInputData(0))->GetTree()->GetReadEntry() );
+  fUPCEvent->SetRunNumber( vEvent->GetRunNumber() );
+
+  //VZERO
+  AliVVZERO *dataVZERO = vEvent->GetVZEROData();
+  if(!dataVZERO) {PostData(2, fHistList); return;}
+
+  fUPCEvent->SetV0ADecision( dataVZERO->GetV0ADecision() );
+  fUPCEvent->SetV0CDecision( dataVZERO->GetV0CDecision() );
+  for (UInt_t iv=0; iv<32; iv++) {
+    if( dataVZERO->BBTriggerV0C((Int_t)iv) ) fUPCEvent->SetBBtriggerV0Cmask(iv);
+    if( dataVZERO->GetBBFlag((Int_t)iv) ) fUPCEvent->SetBBFlagV0Cmask(iv);
+  }
+
+  //ZDC
+  AliVZDC *dataZDC = vEvent->GetZDCData();
+  if(!dataZDC) {PostData(2, fHistList); return;}
+
+  //energy in ZDC
+  Double_t eZnc=0., eZpc=0., eZna=0., eZpa=0.;
+  for(Int_t i=0; i<5; i++) {
+    eZnc += dataZDC->GetZNCTowerEnergy()[i];
+    eZpc += dataZDC->GetZPCTowerEnergy()[i];
+    eZna += dataZDC->GetZNATowerEnergy()[i];
+    eZpa += dataZDC->GetZPATowerEnergy()[i];
+  }
+  fUPCEvent->SetZNCEnergy( eZnc );
+  fUPCEvent->SetZPCEnergy( eZpc );
+  fUPCEvent->SetZNAEnergy( eZna );
+  fUPCEvent->SetZPAEnergy( eZpa );
+
+  //default primary vertex
+  const AliVVertex *vtx = vEvent->GetPrimaryVertex();
+  if(!vtx) {PostData(2, fHistList); return;}
+  Double_t pos[3]; vtx->GetXYZ(pos);
+  Double_t cov[6]; vtx->GetCovarianceMatrix(cov);
+  fUPCEvent->SetPrimaryVertex(pos, vtx->GetChi2perNDF(), cov, vtx->GetNContributors());
+  const char *vtxtitle = vtx->GetTitle();
+  fUPCEvent->SetPrimaryVertexTitle( vtxtitle );
+
+  fCounter->Fill( 4 ); // 4 = events written to the tree (ESD and AOD)
+
+  fUPCTree ->Fill();
+  PostData(1, fUPCTree);
+  PostData(2, fHistList);
+
+}//UserExec
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisTaskUpcFilterSemiforward::RunAOD()
+{
+  //cout<<"#################### AOD event ##################"<<endl;
+
+  //input AOD event
+  AliAODEvent *aodEvent = (AliAODEvent*) InputEvent();
+  if(!aodEvent) return kFALSE;
+
+  fCounter->Fill( 22 ); // 22 = AOD analyzed events
+
+  if(fIsMC) RunAODMC( (TClonesArray*) aodEvent->GetList()->FindObject(AliAODMCParticle::StdBranchName()),
+                      (AliAODMCHeader*) aodEvent->FindListObject(AliAODMCHeader::StdBranchName())
+                    );
+
+  //nominal interaction point
+  static AliAODVertex *vtx0 = 0x0;
+  if( !vtx0 ) {
+    // make a vertex at coordinates 0, 0, 0
+    vtx0 = new AliAODVertex();
+    vtx0->SetX(0.); vtx0->SetY(0.); vtx0->SetZ(0.);
+  }
+
+  //array of tracks for DCAs calculation
+  //static TClonesArray *trackArray = 0x0;
+  //if( !trackArray ) trackArray = new TClonesArray("AliAODTrack", 3); // number of DCAs
+
+  Double_t pxpypz[3];
+  UChar_t maskMan;
+  Double_t xyzDca[2], cov[3];
+  Float_t b[2], covF[3];
+  Int_t nmun=0, ncen=0;
+  // AOD tracks loop
+  for(Int_t itr=0; itr<aodEvent->GetNumberOfTracks(); itr++) {
+    AliAODTrack *trk = aodEvent->GetTrack(itr);
+    if( !trk ) continue;
+
+    //muon track
+    if( trk->IsMuonTrack() ) {
+
+      AliUPCMuonTrack *upcMuon = fUPCEvent->AddMuonTrack();
+      upcMuon->SetPtEtaPhi( trk->Pt(), trk->Eta(), trk->Phi() );
+      upcMuon->SetCharge( trk->Charge() );
+      upcMuon->SetMatchTrigger( trk->GetMatchTrigger() );
+      upcMuon->SetRAtAbsorberEnd( trk->GetRAtAbsorberEnd() );
+      upcMuon->SetChi2perNDF( trk->Chi2perNDF() );
+      upcMuon->SetDCA( trk->DCA() );
+      upcMuon->SetPxDCA( fMuonCuts->IsSelected(trk) );
+
+      nmun++;
+    }
+    //central track
+    else {
+
+      maskMan = 0;
+      if( trk->HasPointOnITSLayer(0) )                 { maskMan |= 1 << 0; }
+      if( trk->HasPointOnITSLayer(1) )                 { maskMan |= 1 << 1; }
+      if( trk->GetStatus() & AliESDtrack::kITSrefit )  { maskMan |= 1 << 2; }
+      if( trk->GetStatus() & AliESDtrack::kTPCrefit )  { maskMan |= 1 << 3; }
+
+      //selection for at least one point in ITS and TPC refit
+      //if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+      //if( !(maskMan & (1 << 3)) ) continue;
+
+      //selection for its refit and tpc refit
+      //if( !(maskMan & (1 << 2)) || !(maskMan & (1 << 3)) ) continue;
+
+      //selection for tpc refit
+      //if( !(maskMan & (1 << 3)) ) continue;
+
+      //selection for at least one point in SPD and ITS refit and TPC refit
+      //if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+      //if( !(maskMan & (1 << 2)) || !(maskMan & (1 << 3)) ) continue;
+
+      //selection for at least one point in SPD and at least one TPC cluster
+      if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+      if( trk->GetTPCNcls() == 0 ) continue;
+
+      trk->GetPxPyPz(pxpypz);
+      AliAODPid *apid = trk->GetDetPid();
+      if(!apid) continue;
+
+      AliUPCTrack *upcTrack = fUPCEvent->AddTrack();
+      upcTrack->SetPxPyPz( pxpypz );
+      upcTrack->SetMaskMan( maskMan );
+      upcTrack->SetFilterMap( trk->GetFilterMap() );
+      upcTrack->SetCharge( trk->Charge() );
+      upcTrack->SetChi2perNDF( trk->Chi2perNDF() );
+      upcTrack->SetTPCmomentum( apid->GetTPCmomentum() );
+      upcTrack->SetTPCsignal( apid->GetTPCsignal() );
+      upcTrack->SetTPCNcls( trk->GetTPCNcls() );
+      upcTrack->SetTPCCrossedRows( (Float_t) trk->GetTPCNCrossedRows() );
+      upcTrack->SetTPCNclsF( trk->GetTPCNclsF() );
+      upcTrack->SetTPCNclsS( trk->GetTPCnclsS() );
+      upcTrack->SetITSClusterMap( trk->GetITSClusterMap() );
+
+      //array for DCA
+      //trackArray->Clear("C");
+      //new((*trackArray)[0]) AliAODTrack(*trk);
+      //new((*trackArray)[1]) AliAODTrack(*trk);
+      //new((*trackArray)[2]) AliAODTrack(*trk);
+
+      //DCA to default primary vertex
+      AliAODTrack *track1 = (AliAODTrack*) trk->Clone("track1");
+      //AliAODTrack *track1 = (AliAODTrack*) trackArray->At( 0 );
+      track1->PropagateToDCA(aodEvent->GetPrimaryVertex(), aodEvent->GetMagneticField(), 9999., xyzDca, cov);
+      for(Int_t i=0; i<2; i++) {b[i] = (Float_t) xyzDca[i]; covF[i] = (Float_t) cov[i];}
+      upcTrack->SetImpactParameters(b, covF);
+      delete track1;
+
+      //DCA to SPD vertex
+      track1 = (AliAODTrack*) trk->Clone("track1");
+      //track1 = (AliAODTrack*) trackArray->At( 1 );
+      track1->PropagateToDCA(aodEvent->GetPrimaryVertexSPD(), aodEvent->GetMagneticField(), 9999., xyzDca, cov);
+      for(Int_t i=0; i<2; i++) {b[i] = (Float_t) xyzDca[i]; covF[i] = (Float_t) cov[i];}
+      upcTrack->SetImpactParametersSPD(b, covF);
+      delete track1;
+
+      //DCA to nominal interaction point
+      track1 = (AliAODTrack*) trk->Clone("track1");
+      //track1 = (AliAODTrack*) trackArray->At( 2 );
+      track1->PropagateToDCA(vtx0, aodEvent->GetMagneticField(), 9999., xyzDca, cov);
+      for(Int_t i=0; i<2; i++) {b[i] = (Float_t) xyzDca[i]; covF[i] = (Float_t) cov[i];}
+      upcTrack->SetImpactParametersIP(b, covF);
+      delete track1;
+
+      ncen++;
+    }
+  }// AOD tracks loop
+
+  //selection for at least one muon or central track
+  if( nmun + ncen < 1 ) return kFALSE;
+
+  //selection for at least one muon and at least one central track
+  //if( nmun < 1 || ncen < 1 ) return kFALSE;
+
+
+  // L0 trigger inputs
+  fUPCEvent->SetL0inputs( aodEvent->GetHeader()->GetL0TriggerInputs() );
+
+  // Tracklets
+  fUPCEvent->SetNumberOfTracklets( aodEvent->GetTracklets()->GetNumberOfTracklets() );
+
+  // AOD ZDC for TDC
+  AliAODZDC *dataZDCAOD = aodEvent->GetZDCData();
+  if(!dataZDCAOD) {PostData(2, fHistList); return kFALSE;}
+
+  Bool_t znctdc = kFALSE, znatdc = kFALSE;
+  if( dataZDCAOD->GetZNCTime() != 0. ) znctdc = kTRUE;
+  if( dataZDCAOD->GetZNATime() != 0. ) znatdc = kTRUE;
+  fUPCEvent->SetZNCtdc( znctdc );
+  fUPCEvent->SetZNAtdc( znatdc );
+  fUPCEvent->SetZPCtdc( kFALSE );
+  fUPCEvent->SetZPAtdc( kFALSE );
+
+  //SPD primary vertex in AOD
+  AliAODVertex *vtx = aodEvent->GetPrimaryVertexSPD();
+  if(!vtx) {PostData(2, fHistList); return kFALSE;}
+  Double_t posVtx[3]; vtx->GetXYZ( posVtx );
+  Double_t covVtx[6]; vtx->GetCovarianceMatrix( covVtx );
+  fUPCEvent->SetPrimaryVertexSPD(posVtx, vtx->GetChi2perNDF(), covVtx, vtx->GetNContributors());
+  const char *vtxtitle = vtx->GetTitle();
+  fUPCEvent->SetPrimaryVertexSPDtitle( vtxtitle );
+
+  return kTRUE;
+
+}//RunAOD
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::RunAODMC(TClonesArray *arrayMC, AliAODMCHeader *headerMC)
+{
+  // run over AOD mc particles
+
+  if( !arrayMC || !headerMC ) return;
+
+  //generated vertex in AOD MC
+  Double_t vtxD[3]; headerMC->GetVertex( vtxD );
+  Float_t vtxF[3]; for(Int_t i=0; i<3; i++) vtxF[i] = (Float_t) vtxD[i];
+  fUPCEvent->SetPrimaryVertexMC( vtxF );
+
+  //loop over mc particles
+  for(Int_t imc=0; imc<arrayMC->GetEntriesFast(); imc++) {
+    AliAODMCParticle *aodmc = (AliAODMCParticle*) arrayMC->At(imc);
+    if(!aodmc) continue;
+
+    if(aodmc->GetMother() >= 0) continue;
+
+    TParticle *part = fUPCEvent->AddMCParticle();
+    part->SetMomentum(aodmc->Px(), aodmc->Py(), aodmc->Pz(), aodmc->E());
+    part->SetProductionVertex(aodmc->Xv(), aodmc->Yv(), aodmc->Zv(), aodmc->T());
+    part->SetFirstMother(aodmc->GetMother());
+    part->SetLastDaughter(aodmc->GetNDaughters());
+    part->SetPdgCode(aodmc->GetPdgCode());
+    part->SetUniqueID(imc);
+  }//loop over mc particles
+
+}//RunAODMC
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisTaskUpcFilterSemiforward::RunESD()
+{
+  //cout<<"#################### ESD event ##################"<<endl;
+
+  // Input ESD event
+  AliESDEvent *esdEvent = (AliESDEvent*) InputEvent();
+  if(!esdEvent) return kFALSE;
+
+  fCounter->Fill( 21 ); // 21 = ESD analyzed events
+
+  if(fIsMC) {
+    fUPCEvent->SetNSPDfiredInner( fTriggerAna->SPDFiredChips(esdEvent,1,kFALSE,1) );
+    fUPCEvent->SetNSPDfiredOuter( fTriggerAna->SPDFiredChips(esdEvent,1,kFALSE,2) );
+
+    RunESDMC();
+  }
+
+  static AliESDVertex *vtx0 = 0x0;
+  if( !vtx0 ) {
+    // make a vertex at coordinates 0, 0, 0
+    vtx0 = new AliESDVertex();
+    vtx0->SetXv(0.); vtx0->SetYv(0.); vtx0->SetZv(0.);
+  }
+
+  // ESD central tracks
+  Double_t pxpypz[3];
+  Float_t b[2]; Float_t cov[3];
+  UChar_t maskMan;
+  UInt_t filterMap;
+  Int_t nmun=0, ncen=0;
+  //ESD central tracks loop
+  for(Int_t itr=0; itr<esdEvent->GetNumberOfTracks(); itr++) {
+    AliESDtrack *eTrack = esdEvent->GetTrack(itr);
+    if( !eTrack ) continue;
+
+    // manual filter
+    maskMan = 0;
+    if( eTrack->HasPointOnITSLayer(0) )                 { maskMan |= 1 << 0; }
+    if( eTrack->HasPointOnITSLayer(1) )                 { maskMan |= 1 << 1; }
+    if( eTrack->GetStatus() & AliESDtrack::kITSrefit )  { maskMan |= 1 << 2; }
+    if( eTrack->GetStatus() & AliESDtrack::kTPCrefit )  { maskMan |= 1 << 3; }
+    if( eTrack->GetKinkIndex(0) > 0 )                   { maskMan |= 1 << 4; } // bit set if track is kink candidate
+
+    //selection for at least one point in ITS and TPC refit
+    //if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+    //if( !(maskMan & (1 << 3)) ) continue;
+
+    //selection for its refit and tpc refit
+    //if( !(maskMan & (1 << 2)) || !(maskMan & (1 << 3)) ) continue;
+
+    //selection for tpc refit
+    //if( !(maskMan & (1 << 3)) ) continue;
+
+    //selection for at least one point in SPD and ITS refit and TPC refit
+    //if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+    //if( !(maskMan & (1 << 2)) || !(maskMan & (1 << 3)) ) continue;
+
+    //selection for at least one point in SPD and at least one TPC cluster
+    if( !(maskMan & (1 << 0)) && !(maskMan & (1 << 1)) ) continue;
+    if( eTrack->GetTPCNcls() == 0 ) continue;
+
+    //central track accepted to write to the UPC event
+
+    // various configurations of AliESDtrackCuts
+    filterMap = 0;
+    for(UInt_t i=0; i<32; i++) {
+      if( !fCutsList[i] ) continue;
+
+      if( fCutsList[i]->AcceptTrack(eTrack) ) { filterMap |= 1 << i; }
+    }
+
+    eTrack->GetPxPyPz(pxpypz);
+
+    //fill UPC track
+    AliUPCTrack *upcTrack = fUPCEvent->AddTrack();
+    upcTrack->SetPxPyPz( pxpypz );
+    upcTrack->SetMaskMan( maskMan );
+    upcTrack->SetFilterMap( filterMap );
+    upcTrack->SetCharge( eTrack->Charge() );
+    upcTrack->SetChi2perNDF( eTrack->GetTPCchi2()/((Double_t) eTrack->GetTPCNcls()) ); // TPC chi2 used to fill this data member in esd
+    upcTrack->SetTPCmomentum( eTrack->GetTPCmomentum() );
+    upcTrack->SetTPCsignal( eTrack->GetTPCsignal() );
+    upcTrack->SetTPCNcls( eTrack->GetTPCNcls() );
+    upcTrack->SetTPCCrossedRows( eTrack->GetTPCCrossedRows() );
+    upcTrack->SetTPCNclsF( eTrack->GetTPCNclsF() );
+    upcTrack->SetTPCNclsS( eTrack->GetTPCnclsS() );
+    upcTrack->SetITSchi2perNDF( eTrack->GetITSchi2()/((Double_t) eTrack->GetNcls(0)) );
+    upcTrack->SetITSClusterMap( eTrack->GetITSClusterMap() );
+
+    //DCA to default primary vertex
+    eTrack->GetImpactParameters(b, cov);
+    upcTrack->SetImpactParameters(b, cov);
+
+    //DCA to SPD vertex
+    AliESDtrack *track1 = (AliESDtrack*) eTrack->Clone("track1");
+    track1->RelateToVertex( esdEvent->GetPrimaryVertexSPD(), esdEvent->GetMagneticField(), 9999. );
+    track1->GetImpactParameters(b, cov);
+    upcTrack->SetImpactParametersSPD(b, cov);
+    delete track1;
+
+    //DCA to nominal interaction point
+    track1 = (AliESDtrack*) eTrack->Clone("track1");
+    track1->RelateToVertex( vtx0, esdEvent->GetMagneticField(), 9999. );
+    track1->GetImpactParameters(b, cov);
+    upcTrack->SetImpactParametersIP(b, cov);
+    delete track1;
+
+    ncen++;
+  } //ESD central tracks loop
+
+  // ESD muon tracks
+  //muon tracks loop
+  for(Int_t itr=0; itr<esdEvent->GetNumberOfMuonTracks(); itr++) {
+    AliESDMuonTrack *mTrack = esdEvent->GetMuonTrack(itr);
+    if( !mTrack ) continue;
+
+    AliUPCMuonTrack *upcMuon = fUPCEvent->AddMuonTrack();
+    upcMuon->SetPtEtaPhi( mTrack->Pt(), mTrack->Eta(), mTrack->Phi() );
+    upcMuon->SetCharge( mTrack->Charge() );
+    upcMuon->SetMatchTrigger( mTrack->GetMatchTrigger() );
+    upcMuon->SetRAtAbsorberEnd( mTrack->GetRAtAbsorberEnd() );
+    upcMuon->SetChi2perNDF( mTrack->GetChi2()/((Double_t) mTrack->GetNDF()) );
+    upcMuon->SetDCA( mTrack->GetDCA() );
+    upcMuon->SetPxDCA( fMuonCuts->IsSelected(mTrack) );
+
+    nmun++;
+  } //muon tracks loop
+
+  //selection for at least one muon or central track
+  if( nmun + ncen < 1 ) return kFALSE;
+
+  //selection for at least one muon and at least one central track
+  //if( nmun < 1 || ncen < 1 ) return kFALSE;
+
+  // L0 trigger inputs
+  fUPCEvent->SetL0inputs( esdEvent->GetHeader()->GetL0TriggerInputs() );
+
+  //Tracklets
+  fUPCEvent->SetNumberOfTracklets( esdEvent->GetMultiplicity()->GetNumberOfTracklets() );
+
+  // ESD ZDC for TDC
+  AliESDZDC *dataZDCESD = esdEvent->GetESDZDC();
+  if(!dataZDCESD) {PostData(2, fHistList); return kFALSE;}
+
+  Bool_t znctdc = kFALSE, zpctdc = kFALSE, znatdc = kFALSE, zpatdc = kFALSE;
+  for(Int_t iz=0;iz<4;iz++) {
+    if( dataZDCESD->GetZDCTDCData(10,iz) ) znctdc = kTRUE;
+    if( dataZDCESD->GetZDCTDCData(11,iz) ) zpctdc = kTRUE;
+    if( dataZDCESD->GetZDCTDCData(12,iz) ) znatdc = kTRUE;
+    if( dataZDCESD->GetZDCTDCData(13,iz) ) zpatdc = kTRUE;
+  }
+  fUPCEvent->SetZNCtdc( znctdc );
+  fUPCEvent->SetZPCtdc( zpctdc );
+  fUPCEvent->SetZNAtdc( znatdc );
+  fUPCEvent->SetZPAtdc( zpatdc );
+
+  //SPD primary vertex in ESD
+  const AliESDVertex *vtx = esdEvent->GetPrimaryVertexSPD();
+  if(!vtx) {PostData(2, fHistList); return kFALSE;}
+  Double_t posVtx[3]; vtx->GetXYZ( posVtx );
+  Double_t covVtx[6]; vtx->GetCovarianceMatrix( covVtx );
+  fUPCEvent->SetPrimaryVertexSPD(posVtx, vtx->GetChi2perNDF(), covVtx, vtx->GetNContributors());
+  const char *vtxtitle = vtx->GetTitle();
+  fUPCEvent->SetPrimaryVertexSPDtitle( vtxtitle );
+
+  return kTRUE;
+
+}//RunESD
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::RunESDMC()
+{
+  // ESD MC particles
+
+  AliMCEvent *mcEvent = MCEvent();
+  if(!mcEvent) {cout<<"Error: no ESD MC found"<<endl; return;}
+
+  //generated vertex
+  TArrayF vtx(3);
+  mcEvent->GenEventHeader()->PrimaryVertex(vtx);
+  fUPCEvent->SetPrimaryVertexMC( vtx.GetArray() );
+
+  //loop over mc particles
+  for(Int_t imc=0; imc<mcEvent->GetNumberOfTracks(); imc++) {
+    AliMCParticle *esdmc = (AliMCParticle*) mcEvent->GetTrack(imc);
+    if(!esdmc) continue;
+
+    if(esdmc->GetMother() >= 0) continue;
+
+    TParticle *part = fUPCEvent->AddMCParticle();
+    part->SetMomentum(esdmc->Px(), esdmc->Py(), esdmc->Pz(), esdmc->E());
+    part->SetProductionVertex(esdmc->Xv(), esdmc->Yv(), esdmc->Zv(), 0.);
+    part->SetFirstMother(esdmc->GetMother());
+    part->SetLastDaughter(esdmc->GetLastDaughter()-esdmc->GetFirstDaughter()+1);
+    part->SetPdgCode(esdmc->PdgCode());
+    part->SetUniqueID(imc);
+  }//loop over mc particles
+
+}//RunESDMC
+
+//_____________________________________________________________________________
+void AliAnalysisTaskUpcFilterSemiforward::Terminate(Option_t *) 
+{
+
+  cout<<"Analysis complete."<<endl;
+}//Terminate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+