1 /**************************************************************************
2 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 //-----------------------------------------------------------------------------
19 /// \class AliAnalysisTaskSingleMu
20 /// Analysis task for single muons in the spectrometer.
21 /// The output is a list of histograms and CF containers.
22 /// The macro class can run on AODs or ESDs.
23 /// If Monte Carlo information is present, some basics checks are performed.
25 /// \author Diego Stocco
26 //-----------------------------------------------------------------------------
28 #define AliAnalysisTaskSingleMu_cxx
30 #include "AliAnalysisTaskSingleMu.h"
40 #include "TObjString.h"
41 #include "TObjArray.h"
44 //#include "TMCProcess.h"
46 #include "TPaveStats.h"
47 #include "TFitResultPtr.h"
49 #include "THashList.h"
52 #include "AliAODEvent.h"
53 #include "AliAODTrack.h"
54 #include "AliAODMCParticle.h"
55 #include "AliMCEvent.h"
56 #include "AliMCParticle.h"
57 #include "AliESDEvent.h"
58 #include "AliESDMuonTrack.h"
59 #include "AliVHeader.h"
60 #include "AliAODMCHeader.h"
64 #include "AliAnalysisManager.h"
67 #include "AliCFContainer.h"
68 #include "AliCFGridSparse.h"
69 #include "AliCFEffGrid.h"
72 #include "AliVAnalysisMuon.h"
73 #include "AliMergeableCollection.h"
74 #include "AliCounterCollection.h"
75 #include "AliMuonEventCuts.h"
76 #include "AliMuonTrackCuts.h"
77 #include "AliAnalysisMuonUtility.h"
81 ClassImp(AliAnalysisTaskSingleMu) // Class implementation in ROOT context
85 //________________________________________________________________________
86 AliAnalysisTaskSingleMu::AliAnalysisTaskSingleMu() :
94 //________________________________________________________________________
95 AliAnalysisTaskSingleMu::AliAnalysisTaskSingleMu(const char *name, const AliMuonTrackCuts& cuts) :
96 AliVAnalysisMuon(name, cuts),
103 TString thetaAbsKeys = "ThetaAbs23 ThetaAbs310";
104 fThetaAbsKeys = thetaAbsKeys.Tokenize(" ");
108 //________________________________________________________________________
109 AliAnalysisTaskSingleMu::~AliAnalysisTaskSingleMu()
115 delete fThetaAbsKeys;
118 //___________________________________________________________________________
119 void AliAnalysisTaskSingleMu::MyUserCreateOutputObjects()
123 TString histoName = "", histoTitle = "";
126 Double_t vzMin = -20., vzMax = 20.;
127 TString vzName("Vz"), vzTitle("Vz"), vzUnits("cm");
129 histoName = "hIpVtx";
130 histo = new TH1F(histoName.Data(), histoName.Data(), nVzBins, vzMin, vzMax);
131 histo->SetXTitle("v_{z} (cm)");
132 AddObjectToCollection(histo, kIPVz);
136 Double_t ptMin = 0., ptMax = 80.;
137 TString ptName("Pt"), ptTitle("p_{T}"), ptUnits("GeV/c");
140 Double_t etaMin = -4.5, etaMax = -2.;
141 TString etaName("Eta"), etaTitle("#eta"), etaUnits("");
144 Double_t phiMin = 0.; Double_t phiMax = 2.*TMath::Pi();
145 TString phiName("Phi"), phiTitle("#phi"), phiUnits("rad");
147 Int_t nChargeBins = 2;
148 Double_t chargeMin = -2, chargeMax = 2.;
149 TString chargeName("Charge"), chargeTitle("charge"), chargeUnits("e");
151 Int_t nThetaAbsEndBins = 2;
152 Double_t thetaAbsEndMin = -0.5, thetaAbsEndMax = 1.5;
153 TString thetaAbsEndName("ThetaAbsEnd"), thetaAbsEndTitle("#theta_{abs}"), thetaAbsEndUnits("a.u.");
155 Int_t nMotherTypeBins = kNtrackSources;
156 Double_t motherTypeMin = -0.5, motherTypeMax = (Double_t)kNtrackSources - 0.5;
157 TString motherType("MotherType"), motherTypeTitle("motherType"), motherTypeUnits("");
159 Int_t nbins[kNvars] = {nPtBins, nEtaBins, nPhiBins, nVzBins, nChargeBins, nThetaAbsEndBins, nMotherTypeBins};
160 Double_t xmin[kNvars] = {ptMin, etaMin, phiMin, vzMin, chargeMin, thetaAbsEndMin, motherTypeMin};
161 Double_t xmax[kNvars] = {ptMax, etaMax, phiMax, vzMax, chargeMax, thetaAbsEndMax, motherTypeMax};
162 TString axisTitle[kNvars] = {ptTitle, etaTitle, phiTitle, vzTitle, chargeTitle, thetaAbsEndTitle, motherTypeTitle};
163 TString axisUnits[kNvars] = {ptUnits, etaUnits, phiUnits, vzUnits, chargeUnits, thetaAbsEndUnits, motherTypeUnits};
165 AliCFContainer* cfContainer = new AliCFContainer("SingleMuContainer","Container for tracks",kNsteps,kNvars,nbins);
167 for ( Int_t idim = 0; idim<kNvars; idim++){
168 histoTitle = Form("%s (%s)", axisTitle[idim].Data(), axisUnits[idim].Data());
169 histoTitle.ReplaceAll("()","");
171 cfContainer->SetVarTitle(idim, histoTitle.Data());
172 cfContainer->SetBinLimits(idim, xmin[idim], xmax[idim]);
175 TString stepTitle[kNsteps] = {"reconstructed", "generated"};
177 TAxis* currAxis = 0x0;
178 for (Int_t istep=0; istep<kNsteps; istep++){
179 cfContainer->SetStepTitle(istep, stepTitle[istep].Data());
180 AliCFGridSparse* gridSparse = cfContainer->GetGrid(istep);
182 currAxis = gridSparse->GetAxis(kHvarMotherType);
183 for ( Int_t ibin=0; ibin<fSrcKeys->GetEntries(); ibin++ ) {
184 currAxis->SetBinLabel(ibin+1, fSrcKeys->At(ibin)->GetName());
188 AddObjectToCollection(cfContainer, kTrackContainer);
190 histoName = "hRecoDimu";
191 TH2* histoDimu = new TH2F(histoName.Data(), histoName.Data(), 24, 0., 120., 30, 0., 150.);
192 histoDimu->SetXTitle("min. p_{T}^{#mu} (GeV/c)");
193 histoDimu->SetYTitle("M_{#mu#mu} (GeV/c^{2})");
194 AddObjectToCollection(histoDimu, kNobjectTypes);
196 histoName = "hGeneratedZ";
197 AddObjectToCollection(histoDimu->Clone(histoName.Data()), kNobjectTypes+1);
200 histoName = "hZmuEtaCorr";
201 histoDimu = new TH2F(histoName.Data(), histoName.Data(), 160, -8., 8., 160,-8., 8.);
202 histoDimu->SetXTitle("#eta_{#mu-}");
203 histoDimu->SetYTitle("#eta_{#mu+}");
204 AddObjectToCollection(histoDimu, kNobjectTypes+2);
206 fMuonTrackCuts->Print("mask");
208 AliInfo(Form("Apply cut on dimuon (60<M_mumu<120 GeV/c^2) to reject Z contribution: %i", fCutOnDimu));
211 //________________________________________________________________________
212 void AliAnalysisTaskSingleMu::ProcessEvent(TString physSel, const TObjArray& selectTrigClasses, TString centrality)
215 /// Fill output objects
218 Double_t ipVz = AliAnalysisMuonUtility::GetVertexSPD(InputEvent())->GetZ();
219 Double_t ipVzMC = MCEvent() ? AliAnalysisMuonUtility::GetMCVertexZ(InputEvent(),MCEvent()) : 0.;
221 for ( Int_t itrig=0; itrig<selectTrigClasses.GetEntries(); ++itrig ) {
222 TString trigClassName = ((TObjString*)selectTrigClasses.At(itrig))->GetString();
223 ((TH1*)GetMergeableObject(physSel, trigClassName, centrality, "hIpVtx"))->Fill(ipVz);
226 // Bool_t isPileupFromSPD = ( fAODEvent && ! fAODEvent->GetTracklets() ) ? InputEvent()->IsPileupFromSPD(3, 0.8, 3., 2., 5.) : InputEvent()->IsPileupFromSPDInMultBins(); // Avoid break when reading Muon AODs (tracklet info is not present and IsPileupFromSPDInMultBins crashes // UNCOMMENT TO REJECT PILEUP
227 // if ( isPileupFromSPD ) return; // UNCOMMENT TO REJECT PILEUP
229 Double_t containerInput[kNvars];
230 AliVParticle* track = 0x0;
232 Int_t nSteps = MCEvent() ? 2 : 1;
233 for ( Int_t istep = 0; istep<nSteps; ++istep ) {
234 Int_t nTracks = ( istep == kStepReconstructed ) ? AliAnalysisMuonUtility::GetNTracks(InputEvent()) : MCEvent()->GetNumberOfTracks();
236 TObjArray selectedTracks(nTracks);
237 TArrayI trackSources(nTracks);
238 for (Int_t itrack = 0; itrack < nTracks; itrack++) {
239 track = ( istep == kStepReconstructed ) ? AliAnalysisMuonUtility::GetTrack(itrack,InputEvent()) : MCEvent()->GetTrack(itrack);
241 // In case of MC we usually ask that the particle is a muon
242 // However, in W or Z simulations, Pythia stores both the initial muon
243 // (before ISR, FSR and kt kick) and the final state one.
244 // The first muon is of course there only for information and should be rejected.
245 // The Pythia code for initial state particles is 21
246 Bool_t isSelected = ( istep == kStepReconstructed ) ? fMuonTrackCuts->IsSelected(track) : ( TMath::Abs(track->PdgCode()) == 13 && AliAnalysisMuonUtility::GetStatusCode(track) != 21 );
247 if ( ! isSelected ) continue;
249 selectedTracks.AddAt(track,itrack);
250 trackSources[itrack] = GetParticleType(track);
254 // Loop on selected tracks
255 TArrayI rejectTrack(nTracks);
256 for ( Int_t itrack=0; itrack<nTracks; itrack++) {
257 track = static_cast<AliVParticle*>(selectedTracks.At(itrack));
258 if ( ! track ) continue;
260 if ( istep == kStepGeneratedMC || fCutOnDimu ) {
262 for ( Int_t jtrack=itrack+1; jtrack<nTracks; jtrack++ ) {
263 AliVParticle* auxTrack = static_cast<AliVParticle*>(selectedTracks.At(jtrack));
264 if ( ! auxTrack ) continue;
265 if ( track->Charge() * auxTrack->Charge() >= 0 ) continue;
267 TLorentzVector dimuPair = AliAnalysisMuonUtility::GetTrackPair(track,auxTrack);
268 Double_t ptMin = TMath::Min(track->Pt(),auxTrack->Pt());
269 Double_t invMass = dimuPair.M();
270 if ( invMass > 60. && invMass < 120. ) {
271 rejectTrack[itrack] = 1;
272 rejectTrack[jtrack] = 1;
274 if ( istep == kStepReconstructed ) {
275 for ( Int_t itrig=0; itrig<selectTrigClasses.GetEntries(); ++itrig ) {
276 TString trigClassName = ((TObjString*)selectTrigClasses.At(itrig))->GetString();
277 if ( ! fMuonTrackCuts->TrackPtCutMatchTrigClass(track, fMuonEventCuts->GetTrigClassPtCutLevel(trigClassName)) || ! fMuonTrackCuts->TrackPtCutMatchTrigClass(auxTrack, fMuonEventCuts->GetTrigClassPtCutLevel(trigClassName)) ) continue;
278 ((TH2*)GetMergeableObject(physSel, trigClassName, centrality, "hRecoDimu"))->Fill(ptMin,invMass);
279 } // loop on triggers
282 if ( trackSources[itrack] == kZbosonMu && trackSources[jtrack] == kZbosonMu ) {
283 Bool_t isAccepted = kTRUE;
284 AliVParticle* muDaughter[2] = {0x0, 0x0};
285 for ( Int_t imu=0; imu<2; imu++ ) {
286 AliVParticle* currPart = ( imu == 0 ) ? track : auxTrack;
287 if ( currPart->Charge() < 0. ) muDaughter[0] = currPart;
288 else muDaughter[1] = currPart;
289 if ( currPart->Eta() < -4.5 || currPart->Eta() > -2. ) {
292 } // loop on muons in the pair
294 Double_t pairRapidity = dimuPair.Rapidity();
295 if ( pairRapidity < -4. || pairRapidity > -2.5 ) isAccepted = kFALSE;
296 //printf("Rapidity Z %g pair %g\n",track->Y(), pairRapidity);
298 for ( Int_t itrig=0; itrig<selectTrigClasses.GetEntries(); ++itrig ) {
299 TString trigClassName = ((TObjString*)selectTrigClasses.At(itrig))->GetString();
300 if ( isAccepted ) ((TH2*)GetMergeableObject(physSel, trigClassName, centrality, "hGeneratedZ"))->Fill(ptMin,invMass);
301 ((TH2*)GetMergeableObject(physSel, trigClassName, centrality, "hZmuEtaCorr"))->Fill(muDaughter[0]->Eta(),muDaughter[1]->Eta());
302 } // loop on selected trig
303 } // both muons from Z
304 } // kStepGeneratedMC
305 } // loop on auxiliary tracks
306 } // apply cut on dimu
307 if ( rejectTrack[itrack] > 0 ) continue;
309 Double_t thetaAbsEndDeg = 0;
310 if ( istep == kStepReconstructed ) {
311 thetaAbsEndDeg = AliAnalysisMuonUtility::GetThetaAbsDeg(track);
314 thetaAbsEndDeg = ( TMath::Pi()-track->Theta() ) * TMath::RadToDeg();
316 Int_t thetaAbsBin = ( thetaAbsEndDeg < 3. ) ? kThetaAbs23 : kThetaAbs310;
318 containerInput[kHvarPt] = track->Pt();
319 containerInput[kHvarEta] = track->Eta();
320 containerInput[kHvarPhi] = track->Phi();
321 containerInput[kHvarVz] = ( istep == kStepReconstructed ) ? ipVz : ipVzMC;
322 containerInput[kHvarCharge] = track->Charge()/3.;
323 containerInput[kHvarThetaAbs] = (Double_t)thetaAbsBin;
324 containerInput[kHvarMotherType] = (Double_t)trackSources[itrack];
326 for ( Int_t itrig=0; itrig<selectTrigClasses.GetEntries(); ++itrig ) {
327 TString trigClassName = ((TObjString*)selectTrigClasses.At(itrig))->GetString();
328 if ( istep == kStepReconstructed && ! fMuonTrackCuts->TrackPtCutMatchTrigClass(track, fMuonEventCuts->GetTrigClassPtCutLevel(trigClassName)) ) continue;
329 ((AliCFContainer*)GetMergeableObject(physSel, trigClassName, centrality, "SingleMuContainer"))->Fill(containerInput,istep);
330 } // loop on selected trigger classes
332 } // loop on container steps
336 //________________________________________________________________________
337 void AliAnalysisTaskSingleMu::Terminate(Option_t *) {
339 /// Draw some histograms at the end.
342 AliVAnalysisMuon::Terminate("");
344 if ( ! fMergeableCollection ) return;
346 TString physSel = fTerminateOptions->At(0)->GetName();
347 TString trigClassName = fTerminateOptions->At(1)->GetName();
348 TString centralityRange = fTerminateOptions->At(2)->GetName();
349 TString furtherOpt = fTerminateOptions->At(3)->GetName();
351 TString minBiasTrig = "";
352 TObjArray* optArr = furtherOpt.Tokenize(" ");
353 TString currName = "";
354 for ( Int_t iopt=0; iopt<optArr->GetEntries(); iopt++ ) {
355 currName = optArr->At(iopt)->GetName();
356 if ( currName.Contains("-B-") || currName.Contains("ANY") ) minBiasTrig = currName;
360 furtherOpt.ToUpper();
361 Bool_t plotChargeAsymmetry = furtherOpt.Contains("ASYM");
363 AliCFContainer* inContainer = static_cast<AliCFContainer*> ( GetSum(physSel,trigClassName,centralityRange,"SingleMuContainer") );
364 if ( ! inContainer ) return;
366 AliCFContainer* cfContainer = inContainer;
368 if ( ! furtherOpt.Contains("GENINTRIGCLASS") && trigClassName != "ANY" ) {
369 // The output container contains both the reconstructed and (in MC)
370 // the generated muons in a specific trigger class.
371 // Since the trigger pt level of the track is matched to the trigger class,
372 // analyzing the MUHigh trigger (for example) is equivalent of analyzing
374 // However, in this way, the generated muons distribution depend
375 // on a condition on the reconstructed track.
376 // If we calculate the Acc.xEff. as the ratio of reconstructed and
377 // generated muons IN A TRIGGER CLASS, we are biasing the final result.
378 // The correct value of Acc.xEff. is hence obtained as the distribution
379 // of reconstructed tracks in a muon trigger class, divided by the
380 // total number of generated class (which is in the "class" ANY).
381 // The following code sets the generated muons as the one in the class ANY.
382 // The feature is the default. If you want the generated muons in the same
383 // trigger class as the generated tracks, use option "GENINTRIGCLASS"
384 AliCFContainer* fullMCcontainer = static_cast<AliCFContainer*> ( GetSum(physSel,"ANY",centralityRange,"SingleMuContainer") );
385 if ( fullMCcontainer ) {
386 cfContainer = static_cast<AliCFContainer*>(cfContainer->Clone("SingleMuContainerCombo"));
387 cfContainer->SetGrid(kStepGeneratedMC,fullMCcontainer->GetGrid(kStepGeneratedMC));
391 AliCFEffGrid* effSparse = new AliCFEffGrid(Form("eff%s", cfContainer->GetName()),Form("Efficiency %s", cfContainer->GetTitle()),*cfContainer);
392 effSparse->CalculateEfficiency(kStepReconstructed, kStepGeneratedMC);
394 AliCFGridSparse* gridSparseArray[3] = {effSparse->GetNum(), effSparse->GetDen(), effSparse};
395 TString gridSparseName[3] = {cfContainer->GetStepTitle(kStepReconstructed), cfContainer->GetStepTitle(kStepGeneratedMC), "Efficiency"};
397 Int_t srcColors[kNtrackSources] = {kBlack, kRed, kSpring, kTeal, kBlue, kViolet, kMagenta, kOrange, kGray};
398 // TString allSrcNames = "";
399 // for ( Int_t isrc=0; isrc<kNtrackSources; ++isrc ) {
400 // if ( ! allSrcNames.IsNull() ) allSrcNames.Append(" ");
401 // allSrcNames += fSrcKeys->At(isrc)->GetName();
410 Bool_t isMC = furtherOpt.Contains("MC");
412 TAxis* srcAxis = gridSparseArray[0]->GetAxis(kHvarMotherType);
413 Int_t unIdBin = srcAxis->GetNbins();
414 for ( Int_t ibin=1; ibin<=srcAxis->GetNbins(); ibin++ ) {
415 currName = srcAxis->GetBinLabel(ibin);
416 if ( currName.Contains("Unidentified") ) unIdBin = ibin;
419 Int_t firstSrcBin = ( isMC ) ? 1 : unIdBin;
420 Int_t lastSrcBin = ( isMC ) ? srcAxis->GetNbins() - 1 : unIdBin;
421 if ( ! isMC ) srcColors[unIdBin-1] = 1;
426 TString chargeNames[3] = {fChargeKeys->At(0)->GetName(), fChargeKeys->At(1)->GetName(), "Total"};
427 THashList histoList[3];
428 for ( Int_t icharge=0; icharge<3; icharge++ ) {
429 histoList[icharge].SetName(chargeNames[icharge].Data());
431 for ( Int_t isrc = firstSrcBin; isrc <= lastSrcBin; ++isrc ) {
432 for ( Int_t icharge=0; icharge<3; ++icharge ) {
433 Int_t icharge1 = ( icharge < 2 ) ? icharge : 0;
434 Int_t icharge2 = ( icharge < 2 ) ? icharge : 1;
435 for ( Int_t igrid=0; igrid<3; ++igrid ) {
436 if ( gridSparseArray[igrid]->GetEntries() == 0. ) break;
437 if ( gridSparseArray[igrid]->IsA() != AliCFEffGrid::Class() ) {
438 SetSparseRange(gridSparseArray[igrid], kHvarEta, "", -3.999, -2.501);
439 SetSparseRange(gridSparseArray[igrid], kHvarMotherType, "", isrc, isrc, "USEBIN");
440 SetSparseRange(gridSparseArray[igrid], kHvarCharge, "", icharge1+1, icharge2+1, "USEBIN");
442 TH1* histo = gridSparseArray[igrid]->Project(kHvarPt, kHvarEta);
443 histo->SetName(Form("hPtEta_%s_%s_%s", gridSparseName[igrid].Data(), srcAxis->GetBinLabel(isrc), chargeNames[icharge].Data()));
444 if ( histo->Integral() > 0 ) histoList[icharge].Add(histo);
445 for ( Int_t iproj=0; iproj<4; ++iproj ) {
446 histo = gridSparseArray[igrid]->Project(iproj);
447 histo->SetName(Form("proj%i_%s_%s_%s", iproj, gridSparseName[igrid].Data(), srcAxis->GetBinLabel(isrc), chargeNames[icharge].Data()));
448 if ( histo->Integral() > 0 ) histoList[icharge].Add(histo);
449 } // loop on projections
450 } // loop on grid sparse
452 } // loop on track sources
454 // Get charge asymmetry or mu+/mu-
455 THashList histoListRatio;
456 TString basePlotName = plotChargeAsymmetry ? "ChargeAsymmetry" : "ChargeRatio";
457 histoListRatio.SetName(basePlotName.Data());
458 Int_t baseCharge = 1;
459 Int_t auxCharge = 1-baseCharge;
460 for ( Int_t ihisto=0; ihisto<histoList[baseCharge].GetEntries(); ihisto++ ) {
461 TObject* obj = histoList[baseCharge].At(ihisto);
462 TString histoName = obj->GetName();
463 if ( histoName.Contains(gridSparseName[2].Data()) ) continue;
464 TString searchName = histoName;
465 searchName.ReplaceAll(fChargeKeys->At(baseCharge)->GetName(), fChargeKeys->At(auxCharge)->GetName());
466 TH1* auxHisto = static_cast<TH1*> (histoList[auxCharge].FindObject(searchName.Data()));
467 if ( ! auxHisto ) continue;
468 histoName.ReplaceAll(fChargeKeys->At(baseCharge)->GetName(),basePlotName.Data());
469 TH1* histo = static_cast<TH1*> (obj->Clone(histoName.Data()));
470 if ( plotChargeAsymmetry ) {
471 histo->Add(auxHisto, -1.);
472 // h2 + h1 = 2xh2 + (h1-h2)
473 auxHisto->Add(auxHisto, histo, 2.);
475 histo->Divide(auxHisto);
476 TString axisTitle = plotChargeAsymmetry ? Form("(%s - %s) / (%s + %s)", fChargeKeys->At(1)->GetName(), fChargeKeys->At(0)->GetName(), fChargeKeys->At(1)->GetName(), fChargeKeys->At(0)->GetName()) : Form("%s / %s", fChargeKeys->At(1)->GetName(), fChargeKeys->At(0)->GetName());
477 axisTitle.ReplaceAll("MuPlus","#mu^{+}");
478 axisTitle.ReplaceAll("MuMinus","#mu^{-}");
479 histo->GetYaxis()->SetTitle(axisTitle.Data());
480 histo->SetStats(kFALSE);
481 histoListRatio.Add(histo);
485 TString histoName = "", drawOpt = "";
486 for ( Int_t itype=0; itype<3; itype++ ) {
487 THashList* currList = 0x0;
489 if ( itype == 1 ) currList = &histoListRatio;
490 else if ( itype == 2 ) currList = &histoList[2];
492 for ( Int_t igrid=0; igrid<3; ++igrid ) {
494 TCanvas* canKine = 0x0;
495 TLegend* legKine = 0x0;
496 for ( Int_t iproj=0; iproj<4; ++iproj ) {
497 for ( Int_t isrc = firstSrcBin; isrc <= lastSrcBin; ++isrc ) {
498 for ( Int_t icharge=0; icharge<nCharges; ++icharge ) {
499 if ( itype == 0 ) currList = &histoList[icharge];
500 histoName = Form("proj%i_%s_%s_%s", iproj, gridSparseName[igrid].Data(), srcAxis->GetBinLabel(isrc), currList->GetName());
501 TH1* histo = static_cast<TH1*>(currList->FindObject(histoName.Data()));
502 if ( ! histo ) continue;
506 currName = Form("%s_%s_%s", GetName(), currList->GetName(), gridSparseName[igrid].Data());
507 canKine = new TCanvas(currName.Data(),currName.Data(),igroup1*xshift,igroup2*yshift,600,600);
508 canKine->Divide(2,2);
509 legKine = new TLegend(0.6, 0.6, 0.8, 0.8);
511 canKine->cd(iproj+1);
513 if ( ( iproj == kHvarPt || iproj == kHvarVz ) && gridSparseArray[igrid]->IsA() != AliCFEffGrid::Class() ) gPad->SetLogy();
515 Bool_t isFirst = ( gPad->GetListOfPrimitives()->GetEntries() == 0 );
516 drawOpt = isFirst ? "e" : "esames";
517 histo->SetLineColor(srcColors[isrc-1]);
518 histo->SetMarkerColor(srcColors[isrc-1]);
519 histo->SetMarkerStyle(20+4*icharge);
520 histo->Draw(drawOpt.Data());
521 TPaveStats* paveStats = (TPaveStats*)histo->FindObject("stats");
522 if ( paveStats ) paveStats->SetTextColor(srcColors[isrc-1]);
524 TString legEntry = ( itype == 0 ) ? fChargeKeys->At(icharge)->GetName() : "";
525 if ( isMC ) legEntry += Form(" %s", srcAxis->GetBinLabel(isrc));
526 if ( ! legEntry.IsNull() ) legKine->AddEntry(histo,legEntry.Data(), "lp");
528 } // loop on mu charge
529 } // loop on track sources
530 } // loop on projections
531 if ( legKine && legKine->GetNRows() > 0 ) {
533 legKine->Draw("same");
535 } // loop on grid sparse
539 for ( Int_t igrid=0; igrid<3; igrid++ ) {
540 if ( gridSparseArray[igrid]->IsA() == AliCFEffGrid::Class() ) continue;
541 SetSparseRange(gridSparseArray[igrid], kHvarCharge, "", 1, gridSparseArray[igrid]->GetAxis(kHvarCharge)->GetNbins(), "USEBIN"); // Reset range
542 } // loop on container steps
544 //////////////////////
545 // Event statistics //
546 //////////////////////
547 printf("\nTotal analyzed events:\n");
548 TString evtSel = Form("trigger:%s", trigClassName.Data());
549 fEventCounters->PrintSum(evtSel.Data());
550 printf("Physics selected analyzed events:\n");
551 evtSel = Form("trigger:%s/selected:yes", trigClassName.Data());
552 fEventCounters->PrintSum(evtSel.Data());
554 TString countPhysSel = "any";
555 if ( physSel.Contains(fPhysSelKeys->At(kPhysSelPass)->GetName()) ) countPhysSel = "yes";
556 else if ( physSel.Contains(fPhysSelKeys->At(kPhysSelReject)->GetName()) ) countPhysSel="no";
557 countPhysSel.Prepend("selected:");
558 printf("Analyzed events vs. centrality:\n");
559 evtSel = Form("trigger:%s/%s", trigClassName.Data(), countPhysSel.Data());
560 fEventCounters->Print("centrality",evtSel.Data(),kTRUE);
563 TString outFilename = Form("/tmp/out%s.root", GetName());
564 TFile* outFile = new TFile(outFilename.Data(),"RECREATE");
565 for ( Int_t icharge=0; icharge<3; icharge++ ) {
566 histoList[icharge].Write();
568 histoListRatio.Write();
570 printf("\nCreating file %s\n", outFilename.Data(
576 if ( ! furtherOpt.Contains("VERTEX") ) return;
577 Int_t firstMother = ( isMC ) ? 0 : kUnidentified;
578 Int_t lastMother = ( isMC ) ? kNtrackSources - 1 : kUnidentified;
580 TH1* eventVertex = (TH1*)GetSum(physSel, minBiasTrig, centralityRange, "hIpVtx");
581 if ( ! eventVertex ) return;
582 Double_t minZ = -9.99, maxZ = 9.99;
583 Double_t meanZ = 0., sigmaZ = 4.;
584 Double_t nSigma = 2.;
585 TString fitOpt = "R0S";
586 Bool_t fixFitRange = kFALSE;
587 TString fitFormula = Form("[0]+[1]*(x+[2])");
590 if ( eventVertex->GetSumw2N() == 0 ) eventVertex->Sumw2();
591 Double_t eventVtxIntegral = eventVertex->Integral(0,eventVertex->GetNbinsX()+1); // Include under/overflow
592 printf("Event vertex integral %.0f\n\n", eventVtxIntegral);
593 if ( eventVtxIntegral <= 0. ) return;
594 eventVertex->Scale(1./eventVtxIntegral);
595 printf("\nFit MB vertex\n");
596 eventVertex->Fit("gaus",fitOpt.Data(),"",minZ,maxZ);
597 TF1* vtxFit = (TF1*)eventVertex->GetListOfFunctions()->FindObject("gaus");
598 currName = "vtxIntegrated";
599 can = new TCanvas(currName.Data(),currName.Data(),igroup1*xshift,igroup2*yshift,600,600);
602 vtxFit->Draw("same");
605 enum {kRecoHF, kRecoBkg, kInputHF, kInputDecay, kRecoAll, kNrecoHistos};
606 TString baseRecoName[kNrecoHistos] = {"RecoHF", "RecoBkg", "InputHF", "InputDecay", "RecoAll"};
607 TArrayI sumMothers[kNrecoHistos];
608 sumMothers[kRecoHF].Set(0);
609 sumMothers[kRecoBkg].Set(0);
610 sumMothers[kInputHF].Set(3);
611 sumMothers[kInputHF][0] = kCharmMu;
612 sumMothers[kInputHF][1] = kBeautyMu;
613 sumMothers[kInputHF][2] = kQuarkoniumMu;
614 sumMothers[kInputDecay].Set(1);
615 sumMothers[kInputDecay][0] = kDecayMu;
616 sumMothers[kRecoAll].Set(srcAxis->GetNbins());
617 for ( Int_t isrc=1; isrc<srcAxis->GetNbins(); ++isrc ) {
618 sumMothers[kRecoAll][isrc-1] = isrc;
621 meanZ = vtxFit->GetParameter(1);
622 sigmaZ = vtxFit->GetParameter(2);
624 Double_t minZfit = ( fixFitRange ) ? minZ : meanZ - nSigma*sigmaZ;
625 Double_t maxZfit = ( fixFitRange ) ? maxZ : meanZ + nSigma*sigmaZ;
627 TF1* fitFunc = new TF1("fitFunc", fitFormula.Data(), minZ, maxZ);
628 fitFunc->SetLineColor(2);
629 fitFunc->SetParNames("Line norm", "Line slope", "Free path");
630 const Double_t kFreePath = 153.; // 150.; // 130.; // cm
631 //fitFunc->SetParameters(0.,1.);
632 fitFunc->FixParameter(2, kFreePath);
634 AliCFGridSparse* gridSparse = cfContainer->GetGrid(kStepReconstructed);
635 TAxis* ptAxis = gridSparse->GetAxis(kHvarPt);
638 Double_t limitNorm = 0., limitSlope = 0.;
639 Int_t firstPtBin = 0, lastPtBin = 0;
641 gStyle->SetOptFit(1111);
643 for ( Int_t itheta=0; itheta<kNthetaAbs; ++itheta ) {
645 SetSparseRange(gridSparse, kHvarThetaAbs, "", itheta+1, itheta+1, "USEBIN");
646 SetSparseRange(gridSparse, kHvarPt, "", 1, ptAxis->GetNbins(), "USEBIN");
647 TH1* recoHisto[kNrecoHistos];
648 for ( Int_t ireco=0; ireco<kNrecoHistos; ++ireco ) {
649 recoHisto[ireco] = gridSparse->Project(kHvarPt);
650 histoName = Form("%sMuon_%s", baseRecoName[ireco].Data(), fThetaAbsKeys->At(itheta)->GetName());
651 recoHisto[ireco]->SetName(histoName.Data());
652 recoHisto[ireco]->SetTitle(histoName.Data());
653 recoHisto[ireco]->Reset();
654 recoHisto[ireco]->Sumw2();
655 for ( Int_t isrc=0; isrc<sumMothers[ireco].GetSize(); ++isrc ) {
656 SetSparseRange(gridSparse, kHvarMotherType, "", sumMothers[ireco][isrc], sumMothers[ireco][isrc], "USEBIN");
657 TH1* auxHisto = gridSparse->Project(kHvarPt);
658 recoHisto[ireco]->Add(auxHisto);
662 SetSparseRange(gridSparse, kHvarMotherType, "", firstMother+1, lastMother+1, "USEBIN");
665 for ( Int_t ibinpt=0; ibinpt<=ptAxis->GetNbins(); ++ibinpt ) {
667 lastPtBin = ( ibinpt == 0 ) ? ptAxis->GetNbins() : ibinpt;
668 SetSparseRange(gridSparse, kHvarPt, "", firstPtBin, lastPtBin, "USEBIN");
669 TH1* histo = gridSparse->Project(kHvarVz);
670 histo->SetName(Form("hVtx_%s_%s_ptBin%i", cfContainer->GetStepTitle(kStepReconstructed), fThetaAbsKeys->At(itheta)->GetName(), ibinpt));
671 if ( histo->Integral() < 100. ) break;
672 printf("\nFit %.2f < pt < %.2f (entries %g)\n", ptAxis->GetBinLowEdge(firstPtBin), ptAxis->GetBinUpEdge(lastPtBin), histo->GetEntries());
673 histo->Divide(eventVertex);
674 Double_t norm = histo->GetBinContent(histo->FindBin(0.));
675 histo->GetYaxis()->SetTitle("#frac{dN_{#mu}}{dv_{z}} / #left(#frac{1}{N_{MB}}#frac{dN_{MB}}{dv_{z}}#right)");
676 slope = ( histo->GetBinContent(histo->FindBin(meanZ+sigmaZ)) -
677 histo->GetBinContent(histo->FindBin(meanZ-sigmaZ)) ) / ( 2. * sigmaZ );
679 if ( slope < 0. ) slope = norm/kFreePath;
681 // Try to fit twice: it fit fails the first time
682 // set some limits on parameters
683 for ( Int_t itry=0; itry<2; itry++ ) {
684 fitFunc->SetParameter(0, norm);
685 fitFunc->SetParameter(1, slope);
687 limitNorm = 2.*histo->Integral();
688 limitSlope = 2.*histo->Integral()/kFreePath;
689 //fitFunc->SetParLimits(0, 0., limitNorm); // REMEMBER TO CHECK
690 fitFunc->SetParLimits(1, 0., limitSlope); // REMEMBER TO CHECK
691 printf("Norm 0. < %f < %f slope 0. < %f < %f\n", norm, limitNorm, slope, limitSlope);
693 TFitResultPtr fitRes = histo->Fit(fitFunc, fitOpt.Data(), "", minZfit, maxZfit);
695 // if ( gMinuit->fCstatu.Contains("CONVERGED") &&
696 if ( ((Int_t)fitRes) == 0 &&
697 fitFunc->GetParameter(0) > 0. &&
698 fitFunc->GetParameter(1) > 0. )
700 else if ( furtherOpt.Contains("REFIT") ) printf("Re-fit with limits\n");
702 printf("Warning: fit problems !!!\n");
707 Double_t p0 = fitFunc->GetParameter(0);
708 Double_t p0err = fitFunc->GetParError(0);
709 Double_t p1 = fitFunc->GetParameter(1);
710 Double_t p1err = fitFunc->GetParError(1);
712 Double_t nullVz = ( p1 != 0. ) ? -p0/p1 : 0.;
713 Double_t nullVzErr = ( p0 != 0. && p1 != 0. ) ? TMath::Abs(nullVz) * TMath::Sqrt(p0err*p0err/(p0*p0) + p1err*p1err/(p1*p1) ) : 0.;
715 printf("Null value at %f +- %f\n", nullVz - kFreePath, nullVzErr);
717 recoHisto[kRecoHF]->SetBinContent(ibinpt, p0);
718 recoHisto[kRecoHF]->SetBinError(ibinpt, p0err);
719 recoHisto[kRecoBkg]->SetBinContent(ibinpt, ( kFreePath + meanZ ) * p1);
720 recoHisto[kRecoBkg]->SetBinError(ibinpt, ( kFreePath + meanZ ) * p1err);
721 if ( currDraw%4 == 0 ){
722 currName = Form("vtx_%s_PtBin%i",fThetaAbsKeys->At(itheta)->GetName(), ibinpt);
723 can = new TCanvas(currName.Data(),currName.Data(),igroup1*xshift,igroup2*yshift,600,600);
726 can->cd( currDraw%4 + 1 );
729 fitFunc->DrawCopy("same");
732 SetSparseRange(gridSparse, kHvarMotherType, "", firstMother+1, lastMother+1, "USEBIN");
733 currName = Form("recoPt_%s",fThetaAbsKeys->At(itheta)->GetName());
734 can = new TCanvas(currName.Data(),currName.Data(),(igroup1+1)*xshift,igroup2*yshift,600,600);
735 TLegend* leg = new TLegend(0.6, 0.6, 0.8, 0.8);
737 for ( Int_t ireco=0; ireco<kNrecoHistos-1; ++ireco ) {
738 if ( recoHisto[ireco]->GetEntries() == 0. ) continue;
739 TH1* ratio = (TH1*)recoHisto[ireco]->Clone(Form("%s_ratio", recoHisto[ireco]->GetName()));
740 ratio->Divide(recoHisto[kRecoAll]);
741 ratio->SetLineColor(srcColors[ireco]);
742 ratio->SetMarkerColor(srcColors[ireco]);
743 ratio->SetMarkerStyle(20+ireco);
744 ratio->GetYaxis()->SetTitle("fraction of total");
745 ratio->Draw(drawOpt.Data());
746 leg->AddEntry(ratio,baseRecoName[ireco].Data(), "lp");
750 } // loop on theta abs