--- /dev/null
+AliAnalysisTaskMuonQA *AddTaskMuonQA(Bool_t selectPhysics = kTRUE, Short_t selectCharge = 0)
+{
+ /// Add AliAnalysisTaskMuonQA to the train (Philippe Pillot)
+
+
+ // Get the pointer to the existing analysis manager via the static access method.
+ AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
+ if(!mgr) {
+ Error("AddTaskMuonQA","AliAnalysisManager not set!");
+ return NULL;
+ }
+
+ // This task run on ESDs
+ TString type = mgr->GetInputEventHandler()->GetDataType();
+ if (!type.Contains("ESD")) {
+ Error("AddTaskMuonQA", "ESD input handler needed!");
+ return NULL;
+ }
+
+ // Create and configure task
+ AliAnalysisTaskMuonQA *task = new AliAnalysisTaskMuonQA("MuonQA");
+ if (!task) {
+ Error("AddTaskMuonQA", "Muon QA task cannot be created!");
+ return NULL;
+ }
+ task->SelectPhysics(selectPhysics);
+ task->SelectCharge(selectCharge);
+
+ // Add task to analysis manager
+ mgr->AddTask(task);
+
+ // Connect input container
+ mgr->ConnectInput(task, 0, mgr->GetCommonInputContainer());
+
+ // Define output file directory
+ TString outputfile = AliAnalysisManager::GetCommonFileName();
+ if ( outputfile.IsNull() ) {
+ Error("AddTaskMuonQA", "Common output file is not defined!");
+ return NULL;
+ }
+ outputfile += ":MUON_QA";
+
+ // Create and connect output containers
+ AliAnalysisDataContainer *cout_histo1 = mgr->CreateContainer("general", TObjArray::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+ AliAnalysisDataContainer *cout_histo2 = mgr->CreateContainer("expert", TObjArray::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+ AliAnalysisDataContainer *cout_trackStat = mgr->CreateContainer("trackCounters", AliCounterCollection::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+ AliAnalysisDataContainer *cout_eventStat = mgr->CreateContainer("eventCounters", AliCounterCollection::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+ mgr->ConnectOutput(task, 1, cout_histo1);
+ mgr->ConnectOutput(task, 2, cout_histo2);
+ mgr->ConnectOutput(task, 3, cout_trackStat);
+ mgr->ConnectOutput(task, 4, cout_eventStat);
+
+ return task;
+}
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+#include <Riostream.h>
+
+// ROOT includes
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TCanvas.h"
+#include "TROOT.h"
+#include "TString.h"
+#include "TObjArray.h"
+#include "TMath.h"
+#include "TFile.h"
+
+// STEER includes
+#include "AliESDEvent.h"
+#include "AliESDMuonTrack.h"
+#include "AliESDMuonCluster.h"
+#include "AliESDInputHandler.h"
+
+// ANALYSIS includes
+#include "AliAnalysisTaskSE.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisManager.h"
+#include "AliAnalysisTaskMuonQA.h"
+#include "AliCounterCollection.h"
+
+ClassImp(AliAnalysisTaskMuonQA)
+
+const Int_t AliAnalysisTaskMuonQA::nCh = 10;
+
+const Int_t AliAnalysisTaskMuonQA::nDE = 1100;
+
+const Float_t AliAnalysisTaskMuonQA::dMax[5] = {176.6, 229.0, 308.84, 418.2, 522.0}; // cm
+
+const Int_t AliAnalysisTaskMuonQA::fgkNTriggerClass = 10;
+
+const char* AliAnalysisTaskMuonQA::fgkTriggerClass[10] =
+{
+ "CBEAMB-ABCE-NOPF-ALL",
+ "CSMBB-ABCE-NOPF-ALL",
+ "CINT1A-ABCE-NOPF-ALL",
+ "CINT1B-ABCE-NOPF-ALL",
+ "CINT1C-ABCE-NOPF-ALL",
+ "CINT1-E-NOPF-ALL",
+ "CMUS1A-ABCE-NOPF-MUON",
+ "CMUS1B-ABCE-NOPF-MUON",
+ "CMUS1C-ABCE-NOPF-MUON",
+ "CMUS1-E-NOPF-MUON"
+};
+
+const char* AliAnalysisTaskMuonQA::fgkTriggerShortName[11] =
+{
+ "CBEAMB",
+ "CSMBB",
+ "CINT1A",
+ "CINT1B",
+ "CINT1C",
+ "CINT1-E",
+ "CMUS1A",
+ "CMUS1B",
+ "CMUS1C",
+ "CMUS1-E",
+ "Other"
+};
+
+//________________________________________________________________________
+AliAnalysisTaskMuonQA::AliAnalysisTaskMuonQA(const char *name) :
+ AliAnalysisTaskSE(name),
+ fList(0x0),
+ fListExpert(0x0),
+ fTrackCounters(0x0),
+ fEventCounters(0x0),
+ fSelectCharge(0),
+ fSelectPhysics(kFALSE)
+{
+ /// Constructor
+
+ // Output slot #1 writes into a TObjArray container
+ DefineOutput(1,TObjArray::Class());
+ // Output slot #2 writes into a TObjArray container
+ DefineOutput(2,TObjArray::Class());
+ // Output slot #3 writes track counters
+ DefineOutput(3,AliCounterCollection::Class());
+ // Output slot #4 writes event counters
+ DefineOutput(4,AliCounterCollection::Class());
+}
+
+//________________________________________________________________________
+AliAnalysisTaskMuonQA::~AliAnalysisTaskMuonQA()
+{
+ /// Destructor
+ delete fList;
+ delete fListExpert;
+ delete fTrackCounters;
+ delete fEventCounters;
+}
+
+//___________________________________________________________________________
+void AliAnalysisTaskMuonQA::UserCreateOutputObjects()
+{
+ /// Create histograms and counters
+
+ fList = new TObjArray(2000);
+ fList->SetOwner();
+ fListExpert = new TObjArray(2000);
+ fListExpert->SetOwner();
+
+ // track info
+ TH1F* hNTracks = new TH1F("hNTracks", "number of tracks;n_{tracks}", 20, 0., 20.);
+ fList->AddAtAndExpand(hNTracks, kNTracks);
+
+ TH1F* hMatchTrig = new TH1F("hMatchTrig", "number of tracks matched with trigger;n_{tracks}", 20, 0., 20.);
+ fList->AddAtAndExpand(hMatchTrig, kMatchTrig);
+
+ TH1F* hSign = new TH1F("hSign", "track sign;sign", 3, -1.5, 1.5);
+ fList->AddAtAndExpand(hSign, kSign);
+
+ TH1F* hDCA = new TH1F("hDCA", "DCA distribution;DCA (cm)", 500, 0., 500.);
+ fList->AddAtAndExpand(hDCA, kDCA);
+
+ TH1F* hP = new TH1F("hP", "momentum distribution;p (GeV/c)", 300, 0., 300.);
+ fList->AddAtAndExpand(hP, kP);
+
+ TH1F* hPt = new TH1F("hPt", "transverse momentum distribution;p_{t} (GeV/c)", 300, 0., 30);
+ fList->AddAtAndExpand(hPt, kPt);
+
+ TH1F* hRapidity = new TH1F("hRapidity", "rapidity distribution;rapidity", 200, -4.5, -2.);
+ fList->AddAtAndExpand(hRapidity, kRapidity);
+
+ TH1F* hThetaX = new TH1F("hThetaX", "#theta_{X} distribution;#theta_{X} (degree)", 360, -180., 180);
+ fList->AddAtAndExpand(hThetaX, kThetaX);
+
+ TH1F* hThetaY = new TH1F("hThetaY", "#theta_{Y} distribution;#theta_{Y} (degree)", 360, -180., 180);
+ fList->AddAtAndExpand(hThetaY, kThetaY);
+
+ TH1F* hChi2 = new TH1F("hChi2", "normalized #chi^{2} distribution;#chi^{2} / ndf", 500, 0., 50.);
+ fList->AddAtAndExpand(hChi2, kChi2);
+
+ TH1F* hProbChi2 = new TH1F("hProbChi2", "distribution of probability of #chi^{2};prob(#chi^{2})", 100, 0., 1.);
+ fList->AddAtAndExpand(hProbChi2, kProbChi2);
+
+ // cluster info
+ TH1F* hNClustersPerTrack = new TH1F("hNClustersPerTrack", "number of associated clusters per track;n_{clusters}", 20, 0., 20.);
+ fList->AddAtAndExpand(hNClustersPerTrack, kNClustersPerTrack);
+
+ TH1F* hNChamberHitPerTrack = new TH1F("hNChamberHitPerTrack", "number of chambers hit per track;n_{chamber hit}", 15, 0., 15.);
+ fList->AddAtAndExpand(hNChamberHitPerTrack, kNChamberHitPerTrack);
+
+ TH1F* hNClustersPerCh = new TH1F("hNClustersPerCh", "averaged number of clusters per chamber per track;chamber ID;<n_{clusters}>", nCh, -0.5, nCh-0.5);
+ hNClustersPerCh->Sumw2();
+ hNClustersPerCh->SetOption("P");
+ hNClustersPerCh->SetMarkerStyle(kFullDotMedium);
+ hNClustersPerCh->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hNClustersPerCh, kNClustersPerCh);
+
+ TH1F* hNClustersPerDE = new TH1F("hNClustersPerDE", "averaged number of clusters per DE per track;DetElem ID;<n_{clusters}>", nDE+1, -0.5, nDE+0.5);
+ hNClustersPerDE->Sumw2();
+ hNClustersPerDE->SetOption("P");
+ hNClustersPerDE->SetMarkerStyle(kFullDotMedium);
+ hNClustersPerDE->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hNClustersPerDE, kNClustersPerDE);
+
+ for (Int_t i = 0; i < nCh; i++) {
+ Float_t rMax = 0.5*dMax[i/2];
+ TH2F* hClusterHitMapInCh = new TH2F(Form("hClusterHitMapInCh%d",i+1), Form("cluster position distribution in chamber %d;X (cm);Y (cm)",i+1),
+ 100, -rMax, rMax, 100, -rMax, rMax);
+ fListExpert->AddAtAndExpand(hClusterHitMapInCh, kClusterHitMapInCh+i);
+
+ TH1F* hClusterChargeInCh = new TH1F(Form("hClusterChargeInCh%d",i+1), Form("cluster charge distribution in chamber %d;charge (fC)",i+1), 100, 0., 1000.);
+ fListExpert->AddAtAndExpand(hClusterChargeInCh, kClusterChargeInCh+i);
+
+ TH1F* hClusterSizeInCh = new TH1F(Form("hClusterSizeInCh%d",i+1), Form("cluster size distribution in chamber %d;size (n_{pads})",i+1), 200, 0., 200.);
+ fListExpert->AddAtAndExpand(hClusterSizeInCh, kClusterSizeInCh+i);
+ }
+
+ TH2F* hClusterChargePerDE = new TH2F("hClusterChargePerDE", "cluster charge distribution per DE;DetElem ID;charge (fC)", nDE+1, -0.5, nDE+0.5, 100, 0., 1000.);
+ fListExpert->AddAtAndExpand(hClusterChargePerDE, kClusterChargePerDE);
+
+ TH2F* hClusterSizePerDE = new TH2F("hClusterSizePerDE", "cluster size distribution per DE;DetElem ID;size (n_{pads})", nDE+1, -0.5, nDE+0.5, 200, 0., 200.);
+ fListExpert->AddAtAndExpand(hClusterSizePerDE, kClusterSizePerDE);
+
+ TH1F* hClusterChargePerChMean = new TH1F("hClusterChargePerChMean", "cluster mean charge per chamber;chamber ID;<charge> (fC)", nCh, -0.5, nCh-0.5);
+ hClusterChargePerChMean->SetOption("P");
+ hClusterChargePerChMean->SetMarkerStyle(kFullDotMedium);
+ hClusterChargePerChMean->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterChargePerChMean, kClusterChargePerChMean);
+
+ TH1F* hClusterChargePerChSigma = new TH1F("hClusterChargePerChSigma", "cluster charge dispersion per chamber;chamber ID;#sigma_{charge} (fC)", nCh, -0.5, nCh-0.5);
+ hClusterChargePerChSigma->SetOption("P");
+ hClusterChargePerChSigma->SetMarkerStyle(kFullDotMedium);
+ hClusterChargePerChSigma->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterChargePerChSigma, kClusterChargePerChSigma);
+
+ TH1F* hClusterChargePerDEMean = new TH1F("hClusterChargePerDEMean", "cluster mean charge per DE;DetElem ID;<charge> (fC)", nDE+1, -0.5, nDE+0.5);
+ hClusterChargePerDEMean->SetOption("P");
+ hClusterChargePerDEMean->SetMarkerStyle(kFullDotMedium);
+ hClusterChargePerDEMean->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterChargePerDEMean, kClusterChargePerDEMean);
+
+ TH1F* hClusterChargePerDESigma = new TH1F("hClusterChargePerDESigma", "cluster charge dispersion per DE;DetElem ID;#sigma_{charge} (fC)", nDE+1, -0.5, nDE+0.5);
+ hClusterChargePerDESigma->SetOption("P");
+ hClusterChargePerDESigma->SetMarkerStyle(kFullDotMedium);
+ hClusterChargePerDESigma->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterChargePerDESigma, kClusterChargePerDESigma);
+
+ TH1F* hClusterSizePerChMean = new TH1F("hClusterSizePerChMean", "cluster mean size per chamber;chamber ID;<size> (n_{pads})", nCh, -0.5, nCh-0.5);
+ hClusterSizePerChMean->SetOption("P");
+ hClusterSizePerChMean->SetMarkerStyle(kFullDotMedium);
+ hClusterSizePerChMean->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterSizePerChMean, kClusterSizePerChMean);
+
+ TH1F* hClusterSizePerChSigma = new TH1F("hClusterSizePerChSigma", "cluster size dispersion per chamber;chamber ID;#sigma_{size} (n_{pads})", nCh, -0.5, nCh-0.5);
+ hClusterSizePerChSigma->SetOption("P");
+ hClusterSizePerChSigma->SetMarkerStyle(kFullDotMedium);
+ hClusterSizePerChSigma->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterSizePerChSigma, kClusterSizePerChSigma);
+
+ TH1F* hClusterSizePerDEMean = new TH1F("hClusterSizePerDEMean", "cluster mean size per DE;DetElem ID;<size> (n_{pads})", nDE+1, -0.5, nDE+0.5);
+ hClusterSizePerDEMean->SetOption("P");
+ hClusterSizePerDEMean->SetMarkerStyle(kFullDotMedium);
+ hClusterSizePerDEMean->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterSizePerDEMean, kClusterSizePerDEMean);
+
+ TH1F* hClusterSizePerDESigma = new TH1F("hClusterSizePerDESigma", "cluster size dispersion per DE;DetElem ID;#sigma_{size} (n_{pads})", nDE+1, -0.5, nDE+0.5);
+ hClusterSizePerDESigma->SetOption("P");
+ hClusterSizePerDESigma->SetMarkerStyle(kFullDotMedium);
+ hClusterSizePerDESigma->SetMarkerColor(kBlue);
+ fList->AddAtAndExpand(hClusterSizePerDESigma, kClusterSizePerDESigma);
+
+ // initialize track counters
+ fTrackCounters = new AliCounterCollection("trackCounters");
+ fTrackCounters->AddRubric("track", "tracker/trigger/matched/any");
+ TString triggerClassNames = "/";
+ for (Int_t i=0; i<=AliAnalysisTaskMuonQA::fgkNTriggerClass; i++)
+ triggerClassNames += Form("%s/",AliAnalysisTaskMuonQA::fgkTriggerShortName[i]);
+ triggerClassNames += "any/";
+ fTrackCounters->AddRubric("trigger", triggerClassNames.Data());
+ fTrackCounters->AddRubric("run", 1000000);
+ fTrackCounters->AddRubric("selected", "yes/no");
+ fTrackCounters->AddRubric("triggerRO", "good/bad");
+ fTrackCounters->Init();
+
+ // initialize event counters
+ fEventCounters = new AliCounterCollection("eventCounters");
+ fEventCounters->AddRubric("event", "muon/any");
+ fEventCounters->AddRubric("trigger", triggerClassNames.Data());
+ fEventCounters->AddRubric("run", 1000000);
+ fEventCounters->AddRubric("selected", "yes/no");
+ fEventCounters->AddRubric("triggerRO", "good/bad");
+ fEventCounters->Init();
+
+ // Post data at least once per task to ensure data synchronisation (required for merging)
+ PostData(1, fList);
+ PostData(2, fListExpert);
+ PostData(3, fTrackCounters);
+ PostData(4, fEventCounters);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonQA::UserExec(Option_t *)
+{
+ /// Called for each event
+
+ // check physics selection
+ Bool_t isPhysicsSelected = (fInputHandler && fInputHandler->IsEventSelected());
+ TString selected = isPhysicsSelected ? "selected:yes" : "selected:no";
+
+ AliESDEvent* fESD = dynamic_cast<AliESDEvent*>(InputEvent());
+ if (!fESD) {
+ Printf("ERROR: fESD not available");
+ return;
+ }
+
+ Int_t nTracks = (Int_t) fESD->GetNumberOfMuonTracks();
+ Int_t nTrackerTracks = 0;
+ Int_t nSelectedTrackerTracks = 0;
+ Int_t nTriggerTracks = 0;
+ Int_t nTrackMatchTrig = 0;
+ Int_t nSelectedTrackMatchTrig = 0;
+
+ // loop over tracks and fill histograms
+ for (Int_t iTrack = 0; iTrack < nTracks; ++iTrack) {
+
+ // --- fill counters for all tracks ---
+
+ // get the ESD track and skip "ghosts"
+ AliESDMuonTrack* esdTrack = fESD->GetMuonTrack(iTrack);
+ if (!esdTrack->ContainTrackerData()) {
+ nTriggerTracks++;
+ continue;
+ }
+
+ nTrackerTracks++;
+
+ if (esdTrack->ContainTriggerData()) {
+ nTriggerTracks++;
+ nTrackMatchTrig++;
+ }
+
+ // --- apply selections and fill histograms with selected tracks ---
+
+ // select on "physics" before filling histograms
+ if (fSelectPhysics && !isPhysicsSelected) continue;
+
+ // select on track charge
+ if (fSelectCharge*esdTrack->Charge() < 0) continue;
+
+ nSelectedTrackerTracks++;
+ if (esdTrack->ContainTriggerData()) nSelectedTrackMatchTrig++;
+
+ ((TH1F*)fList->UncheckedAt(kP))->Fill(esdTrack->P());
+ ((TH1F*)fList->UncheckedAt(kPt))->Fill(esdTrack->Pt());
+ ((TH1F*)fList->UncheckedAt(kRapidity))->Fill(esdTrack->Y());
+ Int_t ndf = 2 * esdTrack->GetNHit() - 5;
+ ((TH1F*)fList->UncheckedAt(kChi2))->Fill(esdTrack->GetChi2()/ndf);
+ ((TH1F*)fList->UncheckedAt(kProbChi2))->Fill(TMath::Prob(esdTrack->GetChi2(),ndf));
+ ((TH1F*)fList->UncheckedAt(kThetaX))->Fill(ChangeThetaRange(esdTrack->GetThetaXUncorrected()));
+ ((TH1F*)fList->UncheckedAt(kThetaY))->Fill(ChangeThetaRange(esdTrack->GetThetaYUncorrected()));
+ ((TH1F*)fList->UncheckedAt(kNClustersPerTrack))->Fill(esdTrack->GetNHit());
+ ((TH1F*)fList->UncheckedAt(kSign))->Fill(esdTrack->Charge());
+ ((TH1F*)fList->UncheckedAt(kDCA))->Fill(esdTrack->GetDCA());
+
+ Int_t nChamberHit = 0;
+ for (Int_t ich=0; ich<10; ich++) if (esdTrack->IsInMuonClusterMap(ich)) nChamberHit++;
+ ((TH1F*)fList->UncheckedAt(kNChamberHitPerTrack))->Fill(nChamberHit);
+
+ // what follows concern clusters
+ if(!esdTrack->ClustersStored()) continue;
+
+ AliESDMuonCluster *esdCluster = (AliESDMuonCluster*) esdTrack->GetClusters().First();
+ while (esdCluster) {
+
+ Int_t chId = esdCluster->GetChamberId();
+ Int_t deId = esdCluster->GetDetElemId();
+
+ ((TH1F*)fList->UncheckedAt(kNClustersPerCh))->Fill(chId);
+ ((TH1F*)fList->UncheckedAt(kNClustersPerDE))->Fill(deId);
+
+ ((TH1F*)fListExpert->UncheckedAt(kClusterHitMapInCh+chId))->Fill(esdCluster->GetX(), esdCluster->GetY());
+
+ ((TH1F*)fListExpert->UncheckedAt(kClusterChargeInCh+chId))->Fill(esdCluster->GetCharge());
+ ((TH1F*)fListExpert->UncheckedAt(kClusterChargePerDE))->Fill(deId, esdCluster->GetCharge());
+
+ if (esdCluster->PadsStored()) { // discard clusters with pad not stored in ESD
+ ((TH1F*)fListExpert->UncheckedAt(kClusterSizeInCh+chId))->Fill(esdCluster->GetNPads());
+ ((TH1F*)fListExpert->UncheckedAt(kClusterSizePerDE))->Fill(deId, esdCluster->GetNPads());
+ }
+
+ esdCluster = (AliESDMuonCluster*) esdTrack->GetClusters().After(esdCluster);
+ }
+
+ }
+
+ ((TH1F*)fList->UncheckedAt(kNTracks))->Fill(nSelectedTrackerTracks);
+ ((TH1F*)fList->UncheckedAt(kMatchTrig))->Fill(nSelectedTrackMatchTrig);
+
+ // fill event counters
+ TString triggerRO = (nTriggerTracks < 10) ? "triggerRO:good" : "triggerRO:bad";
+
+ fEventCounters->Count(Form("event:any/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+
+ Bool_t triggerFired = kFALSE;
+ for (Int_t i=0; i<10; i++) {
+ if (fESD->IsTriggerClassFired(AliAnalysisTaskMuonQA::fgkTriggerClass[i])) {
+ fEventCounters->Count(Form("event:any/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+ triggerFired = kTRUE;
+ }
+ }
+ if (!triggerFired) {
+ fEventCounters->Count(Form("event:any/trigger:other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+ }
+
+ if (nTracks > 0) {
+
+ // fill event counters
+ fEventCounters->Count(Form("event:muon/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+
+ // fill track counters
+ fTrackCounters->Count(Form("track:tracker/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks);
+ fTrackCounters->Count(Form("track:trigger/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTriggerTracks);
+ fTrackCounters->Count(Form("track:matched/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackMatchTrig);
+ fTrackCounters->Count(Form("track:any/trigger:any/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks+nTriggerTracks);
+
+ Bool_t triggerFiredForTrack = kFALSE;
+ for (Int_t i=0; i<AliAnalysisTaskMuonQA::fgkNTriggerClass; i++) {
+
+ if (fESD->IsTriggerClassFired(AliAnalysisTaskMuonQA::fgkTriggerClass[i])) {
+
+ // fill event counters
+ fEventCounters->Count(Form("event:muon/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+
+ // fill track counters
+ fTrackCounters->Count(Form("track:tracker/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks);
+ fTrackCounters->Count(Form("track:trigger/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTriggerTracks);
+ fTrackCounters->Count(Form("track:matched/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackMatchTrig);
+ fTrackCounters->Count(Form("track:any/trigger:%s/run:%d/%s/%s", AliAnalysisTaskMuonQA::fgkTriggerShortName[i], fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks+nTriggerTracks);
+
+ triggerFiredForTrack = kTRUE;
+
+ }
+
+ }
+
+ if (!triggerFiredForTrack) {
+
+ // fill event counters
+ fEventCounters->Count(Form("event:muon/trigger:other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()));
+
+ // fill track counters
+ fTrackCounters->Count(Form("track:tracker/trigger:Other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks);
+ fTrackCounters->Count(Form("track:trigger/trigger:Other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTriggerTracks);
+ fTrackCounters->Count(Form("track:matched/trigger:Other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackMatchTrig);
+ fTrackCounters->Count(Form("track:any/trigger:Other/run:%d/%s/%s", fCurrentRunNumber, selected.Data(), triggerRO.Data()), nTrackerTracks+nTriggerTracks);
+
+ }
+
+ }
+
+ // Post final data. It will be written to a file with option "RECREATE"
+ PostData(1, fList);
+ PostData(2, fListExpert);
+ PostData(3, fTrackCounters);
+ PostData(4, fEventCounters);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonQA::Terminate(Option_t *)
+{
+ /// Normalize histograms
+ /// Draw result to the screen
+ /// Print statistics
+
+ // recover output objects
+ fList = static_cast<TObjArray*> (GetOutputData(1));
+ fListExpert = static_cast<TObjArray*> (GetOutputData(2));
+ if (!fList || !fListExpert) return;
+ fTrackCounters = static_cast<AliCounterCollection*> (GetOutputData(3));
+ fEventCounters = static_cast<AliCounterCollection*> (GetOutputData(4));
+
+ // global statistic
+ if (fTrackCounters && fEventCounters) {
+ if (!gROOT->IsBatch()) {
+ cout<<"whole statistics without selection:"<<endl;
+ fEventCounters->Print("trigger/event");
+ fTrackCounters->Print("trigger/track");
+ cout<<"whole statistics of selected events:"<<endl;
+ fEventCounters->Print("trigger/event","selected:yes");
+ fTrackCounters->Print("trigger/track","selected:yes");
+ new TCanvas();
+ fEventCounters->Draw("event","trigger","");
+ new TCanvas();
+ fTrackCounters->Draw("track","trigger","");
+ new TCanvas();
+ fEventCounters->Draw("event","trigger","selected:yes");
+ new TCanvas();
+ fTrackCounters->Draw("track","trigger","selected:yes");
+ }
+ }
+
+ // normalize histograms and fill summary plots
+ Float_t nTracks = ((TH1F*)fList->UncheckedAt(kNClustersPerTrack))->GetEntries();
+ if (nTracks > 0.) {
+ ((TH1F*)fList->UncheckedAt(kNClustersPerCh))->Scale(1./nTracks);
+ ((TH1F*)fList->UncheckedAt(kNClustersPerDE))->Scale(1./nTracks);
+ }
+
+ // fill summary plots per chamber
+ TH1* hClusterChargePerChMean = ((TH1F*)fList->UncheckedAt(kClusterChargePerChMean));
+ TH1* hClusterChargePerChSigma = ((TH1F*)fList->UncheckedAt(kClusterChargePerChSigma));
+ TH1* hClusterSizePerChMean = ((TH1F*)fList->UncheckedAt(kClusterSizePerChMean));
+ TH1* hClusterSizePerChSigma = ((TH1F*)fList->UncheckedAt(kClusterSizePerChSigma));
+ for (Int_t iCh = 0; iCh < nCh; iCh++) {
+
+ TH1* hClusterChargeInCh = ((TH1F*)fListExpert->UncheckedAt(kClusterChargeInCh+iCh));
+ hClusterChargePerChMean->SetBinContent(iCh+1, hClusterChargeInCh->GetMean());
+ hClusterChargePerChMean->SetBinError(iCh+1, hClusterChargeInCh->GetMeanError());
+ hClusterChargePerChSigma->SetBinContent(iCh+1, hClusterChargeInCh->GetRMS());
+ hClusterChargePerChSigma->SetBinError(iCh+1, hClusterChargeInCh->GetRMSError());
+
+ TH1* hClusterSizeInCh = ((TH1F*)fListExpert->UncheckedAt(kClusterSizeInCh+iCh));
+ hClusterSizePerChMean->SetBinContent(iCh+1, hClusterSizeInCh->GetMean());
+ hClusterSizePerChMean->SetBinError(iCh+1, hClusterSizeInCh->GetMeanError());
+ hClusterSizePerChSigma->SetBinContent(iCh+1, hClusterSizeInCh->GetRMS());
+ hClusterSizePerChSigma->SetBinError(iCh+1, hClusterSizeInCh->GetRMSError());
+
+ }
+
+ // fill summary plots per DE
+ TH2F* hClusterChargePerDE = ((TH2F*)fListExpert->UncheckedAt(kClusterChargePerDE));
+ TH1F* hClusterChargePerDEMean = ((TH1F*)fList->UncheckedAt(kClusterChargePerDEMean));
+ TH1F* hClusterChargePerDESigma = ((TH1F*)fList->UncheckedAt(kClusterChargePerDESigma));
+ TH2F* hClusterSizePerDE = ((TH2F*)fListExpert->UncheckedAt(kClusterSizePerDE));
+ TH1F* hClusterSizePerDEMean = ((TH1F*)fList->UncheckedAt(kClusterSizePerDEMean));
+ TH1F* hClusterSizePerDESigma = ((TH1F*)fList->UncheckedAt(kClusterSizePerDESigma));
+ for (Int_t iDE = 1; iDE < nDE+1; iDE++) {
+
+ TH1D *tmp = hClusterChargePerDE->ProjectionY("tmp",iDE,iDE,"e");
+ if (tmp->GetEntries() > 10.) {
+ hClusterChargePerDEMean->SetBinContent(iDE, tmp->GetMean());
+ hClusterChargePerDEMean->SetBinError(iDE, tmp->GetMeanError());
+ hClusterChargePerDESigma->SetBinContent(iDE, tmp->GetRMS());
+ hClusterChargePerDESigma->SetBinError(iDE, tmp->GetRMSError());
+ }
+ delete tmp;
+
+ tmp = hClusterSizePerDE->ProjectionY("tmp",iDE,iDE,"e");
+ if (tmp->GetEntries() > 10.) {
+ hClusterSizePerDEMean->SetBinContent(iDE, tmp->GetMean());
+ hClusterSizePerDEMean->SetBinError(iDE, tmp->GetMeanError());
+ hClusterSizePerDESigma->SetBinContent(iDE, tmp->GetRMS());
+ hClusterSizePerDESigma->SetBinError(iDE, tmp->GetRMSError());
+ }
+ delete tmp;
+
+ }
+
+ TFile *histoFile = new TFile("histo.root", "RECREATE");
+ histoFile->mkdir("general","general");
+ histoFile->cd("general");
+ fList->Write();
+ histoFile->mkdir("expert","expert");
+ histoFile->cd("expert");
+ fListExpert->Write();
+ histoFile->Close();
+
+}
+
+//________________________________________________________________________
+Double_t AliAnalysisTaskMuonQA::ChangeThetaRange(Double_t theta)
+{
+ if(theta < -2.5) return (theta / TMath::Pi() + 1.) * 180.;
+ else if(theta > 2.5) return (theta / TMath::Pi() - 1.) * 180.;
+ else return theta / TMath::Pi() * 180.;
+}
+
--- /dev/null
+#ifndef ALIANALYSISTASKMUONQA_H
+#define ALIANALYSISTASKMUONQA_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/// \ingroup muondep
+/// \class AliAnalysisTaskMuonQA
+/// \brief Quality assurance of MUON ESDs
+//Author: Philippe Pillot - SUBATECH Nantes
+
+class TObjArray;
+class AliCounterCollection;
+
+class AliAnalysisTaskMuonQA : public AliAnalysisTaskSE {
+public:
+
+ AliAnalysisTaskMuonQA(const char *name = "MuonQA");
+ virtual ~AliAnalysisTaskMuonQA();
+
+ virtual void UserCreateOutputObjects();
+ virtual void UserExec(Option_t *);
+ virtual void Terminate(Option_t *);
+
+ void SelectCharge(Short_t charge = 0) {fSelectCharge = charge;}
+ void SelectPhysics(Bool_t flag = kTRUE) {fSelectPhysics = flag;}
+
+private:
+
+ /// Not implemented
+ AliAnalysisTaskMuonQA(const AliAnalysisTaskMuonQA& rhs);
+ /// Not implemented
+ AliAnalysisTaskMuonQA& operator = (const AliAnalysisTaskMuonQA& rhs);
+
+ Double_t ChangeThetaRange(Double_t theta);
+
+private:
+
+ enum EESD {
+ kNTracks = 0, ///< number of tracks
+ kMatchTrig = 1, ///< number of tracks matched with trigger
+ kSign = 2, ///< track sign
+ kDCA = 3, ///< DCA distribution
+ kP = 4, ///< P distribution
+ kPt = 5, ///< Pt distribution
+ kRapidity = 6, ///< rapidity distribution
+ kThetaX = 7, ///< thetaX distribution
+ kThetaY = 8, ///< thetaY distribution
+ kChi2 = 9, ///< normalized chi2 distribution
+ kProbChi2 = 10, ///< distribution of probability of chi2
+
+ kNClustersPerTrack = 11, ///< number of clusters per track
+ kNChamberHitPerTrack = 12, ///< number of chamber hit per track
+ kNClustersPerCh = 13, ///< number of clusters per chamber per track
+ kNClustersPerDE = 14, ///< number of clusters per DE per track
+ kClusterHitMapInCh = 15, ///< cluster position distribution in chamber i
+ kClusterChargeInCh = 25, ///< cluster charge distribution in chamber i
+ kClusterChargePerChMean = 35, ///< cluster charge per Ch: mean
+ kClusterChargePerChSigma = 36, ///< cluster charge per Ch: dispersion
+ kClusterChargePerDE = 37, ///< cluster charge distribution per DE
+ kClusterChargePerDEMean = 38, ///< cluster charge per DE: mean
+ kClusterChargePerDESigma = 39, ///< cluster charge per DE: dispersion
+ kClusterSizeInCh = 40, ///< cluster size distribution in chamber i
+ kClusterSizePerChMean = 50, ///< cluster size per Ch: mean
+ kClusterSizePerChSigma = 51, ///< cluster size per Ch: dispersion
+ kClusterSizePerDE = 52, ///< cluster size distribution per DE
+ kClusterSizePerDEMean = 53, ///< cluster size per DE: mean
+ kClusterSizePerDESigma = 54 ///< cluster size per DE: dispersion
+ };
+
+ TObjArray* fList; //!< List of output object for everybody
+ TObjArray* fListExpert; //!< List of output object for experts
+
+ AliCounterCollection* fTrackCounters; //!< track statistics
+ AliCounterCollection* fEventCounters; //!< event statistics
+
+ Short_t fSelectCharge; ///< Fill histograms only with negative/position tracks (0=all)
+ Bool_t fSelectPhysics; ///< Fill histograms only with track passing the physics selection
+
+ static const Int_t nCh; ///< number of tracking chambers
+ static const Int_t nDE; ///< number of DE
+ static const Float_t dMax[5]; ///< maximum diameter of each station
+ static const Int_t fgkNTriggerClass; ///< number of trigger class we consider
+ static const char* fgkTriggerClass[10]; ///< full trigger class name
+ static const char* fgkTriggerShortName[11]; ///< short trigger class name for counters
+
+ ClassDef(AliAnalysisTaskMuonQA, 1);
+};
+
+#endif
+
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+//-----------------------------------------------------------------------------
+/// \class AliCounterCollection
+///
+/// generic class to handle a collection of counters
+///
+/// \author Philippe Pillot
+//-----------------------------------------------------------------------------
+
+#include "AliCounterCollection.h"
+
+#include <AliLog.h>
+
+#include <TString.h>
+#include <TObjString.h>
+#include <TObjArray.h>
+#include <THnSparse.h>
+#include <THashList.h>
+#include <TArrayI.h>
+#include <TH1D.h>
+#include <TH2D.h>
+#include <TCollection.h>
+
+ClassImp(AliCounterCollection)
+
+//-----------------------------------------------------------------------
+AliCounterCollection::AliCounterCollection(const char* name) :
+TNamed(name,name),
+fRubrics(new THashList(10)),
+fRubricsSize(new TArrayI(10)),
+fCounters(0x0)
+{
+ /// Constructor
+ fRubrics->SetOwner();
+}
+
+//-----------------------------------------------------------------------
+AliCounterCollection::~AliCounterCollection()
+{
+ /// Destructor
+ delete fRubrics;
+ delete fRubricsSize;
+ delete fCounters;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Clear(Option_t*)
+{
+ /// Clear counters
+ fRubrics->Clear();
+ fRubricsSize->Reset();
+ delete fCounters; fCounters = 0x0;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::AddRubric(TString name, TString listOfKeyWords)
+{
+ /// Add a new rubric with the complete list of related key words separated by "/".
+ /// If the key word "any" is not defined, the overall statistics is
+ /// assumed to be the sum of the statistics under each key word.
+
+ name.ToUpper();
+ listOfKeyWords.ToUpper();
+
+ if (fRubrics->Contains(name.Data())) {
+ AliError(Form("rubric named %s already exist",name.Data()));
+ return;
+ }
+
+ // add the list of autorized key words
+ TObjArray* rubric = listOfKeyWords.Tokenize("/");
+ CleanListOfStrings(rubric);
+ rubric->SetName(name.Data());
+ Int_t nRubrics = fRubrics->GetSize();
+ rubric->SetUniqueID(nRubrics);
+ fRubrics->AddLast(rubric);
+
+ // save the number of autorized key words (expand the array if needed)
+ if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
+ (*fRubricsSize)[nRubrics] = rubric->GetEntriesFast();
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::AddRubric(TString name, Int_t maxNKeyWords)
+{
+ /// Add a new rubric containing at maximum maxNKeyWords key words.
+ /// Key words will be added as the counters get filled until the maximum is reached.
+ /// If the key word "any" is never defined, the overall statistics is
+ /// assumed to be the sum of the statistics under each key word.
+
+ name.ToUpper();
+
+ if (fRubrics->Contains(name.Data())) {
+ AliError(Form("rubric named %s already exist",name.Data()));
+ return;
+ }
+
+ // create the empty rubric
+ TObjString* rubric = new TObjString(name.Data());
+ Int_t nRubrics = fRubrics->GetSize();
+ rubric->SetUniqueID(nRubrics);
+ fRubrics->AddLast(rubric);
+
+ // save the maximum number of autorized key words
+ if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
+ (*fRubricsSize)[nRubrics] = maxNKeyWords;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Init()
+{
+ /// Initialize the internal counters from the added rubrics.
+
+ // create the counters
+ delete fCounters;
+ fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0);
+
+ // loop over axis
+ TObject* rubric = 0x0;
+ TIter nextRubric(fRubrics);
+ while ((rubric = nextRubric())) {
+ TAxis* axis = fCounters->GetAxis((Int_t)rubric->GetUniqueID());
+
+ // set axis name
+ axis->SetName(rubric->GetName());
+
+ // set labels if already known
+ TObjArray* keyWords = dynamic_cast<TObjArray*>(rubric);
+ if (keyWords) {
+ TObjString* label = 0x0;
+ Int_t bin = 1;
+ TIter nextLabel(keyWords);
+ while ((label = static_cast<TObjString*>(nextLabel()))) axis->SetBinLabel(bin++, label->String().Data());
+ }
+
+ }
+
+}
+
+//-----------------------------------------------------------------------
+const Int_t* AliCounterCollection::FindBins(const TString& externalKey, Bool_t allocate, Int_t& nEmptySlots)
+{
+ /// Return the corresponding bins ordered by rubric or 0x0 if externalKey is not valid.
+ /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
+ /// If allocate = kTRUE, new key words are added to the corresponding rubric if possible.
+ /// If a rubric is not filled in, the coresponding slot contain -1 in the array.
+ /// It is the responsability of the user to delete the returned array.
+
+ // produce an empty array of keys
+ Int_t nRubrics = fRubrics->GetSize();
+ Int_t* bins = new Int_t[nRubrics];
+ memset(bins, -1, sizeof(Int_t) * nRubrics);
+ nEmptySlots = nRubrics;
+ Bool_t isValid = kTRUE;
+
+ // get the list of rubric:keyWord pairs
+ TObjArray* rubricKeyPairs = externalKey.Tokenize("/");
+
+ // loop over each rubric:keyWord pair
+ TObjString* pair = 0x0;
+ TIter next(rubricKeyPairs);
+ while ((pair = static_cast<TObjString*>(next()))) {
+
+ // get both rubric and associated key word
+ TObjArray* rubricKeyPair = pair->String().Tokenize(":");
+
+ // check the format of the pair
+ if (rubricKeyPair->GetEntriesFast() != 2) {
+ AliError("invalid key format");
+ isValid = kFALSE;
+ delete rubricKeyPair;
+ break;
+ }
+
+ // get the axis corresponding to that rubric
+ Int_t dim = FindDim(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String());
+ if (dim < 0) {
+ isValid = kFALSE;
+ delete rubricKeyPair;
+ break;
+ }
+
+ // find the bin corresponding to that key word
+ Int_t bin = FindBin(dim, static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String(), allocate);
+ if (bin < 0) {
+ isValid = kFALSE;
+ delete rubricKeyPair;
+ break;
+ }
+
+ // check if the array of keys already contains something for that rubric
+ if (bins[dim] >= 0) {
+ AliWarning("key already given for that rubric --> ignored");
+ delete rubricKeyPair;
+ continue;
+ }
+
+ // store the corresponding bin for that slot
+ bins[dim] = bin;
+ nEmptySlots--;
+
+ // clean memory
+ delete rubricKeyPair;
+ }
+
+ // delete the array in case of problem
+ if (!isValid) {
+ delete[] bins;
+ bins = 0x0;
+ nEmptySlots = nRubrics;
+ }
+
+ // clean memory
+ delete rubricKeyPairs;
+
+ return bins;
+}
+
+//-----------------------------------------------------------------------
+Int_t AliCounterCollection::FindDim(const TString& rubricName) const
+{
+ /// Return the dimension corresponding to that rubric (or -1 in case of failure).
+ TObject* rubric = fRubrics->FindObject(rubricName.Data());
+ if (!rubric) {
+ AliError(Form("invalid rubric: %s",rubricName.Data()));
+ return -1;
+ }
+ return (Int_t) rubric->GetUniqueID();
+}
+
+//-----------------------------------------------------------------------
+Int_t AliCounterCollection::FindBin(Int_t dim, const TString& keyWord, Bool_t allocate)
+{
+ /// Return the bin number corresponding to that key word (or -1 in case of failure).
+ /// If allocate = kTRUE, try to add the key word if possible.
+
+ TAxis* axis = fCounters->GetAxis(dim);
+
+ // look for the bin corresponding to keyWord
+ THashList* labels = axis->GetLabels();
+ TObjString* label = (labels) ? static_cast<TObjString*>(labels->FindObject(keyWord.Data())) : 0x0;
+ Int_t bin = (label) ? (Int_t)label->GetUniqueID() : -1;
+
+ // in case the keyWord does not exist, try to add it if required
+ if (bin<0 && allocate) {
+ Int_t nLabels = (labels) ? labels->GetSize() : 0;
+ if (nLabels < axis->GetNbins()) {
+ bin = nLabels+1;
+ axis->SetBinLabel(bin, keyWord.Data());
+ }
+ }
+
+ if (bin<0) AliError(Form("invalid key word: %s:%s",axis->GetName(),keyWord.Data()));
+
+ return bin;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::CleanListOfStrings(TObjArray* list)
+{
+ /// Make sure all strings appear only once in this list
+
+ // remove multiple-occurrence
+ Int_t nEntries = list->GetEntriesFast();
+ for (Int_t i = 0; i < nEntries; i++) {
+ TObjString* entry1 = static_cast<TObjString*>(list->UncheckedAt(i));
+ if (!entry1) continue;
+ for (Int_t j = i+1; j < nEntries; j++) {
+ TObjString* entry2 = static_cast<TObjString*>(list->UncheckedAt(j));
+ if (entry2 && entry2->IsEqual(entry1)) {
+ AliWarning(Form("multiple-occurence of string \"%s\" --> removed",entry2->String().Data()));
+ list->RemoveAt(j);
+ }
+ }
+ }
+
+ // remove empty slots
+ list->Compress();
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Count(TString externalKey, Int_t value)
+{
+ /// Add "value" to the counter referenced by "externalKey".
+ /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
+
+ if (value < 1) return;
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ externalKey.ToUpper();
+
+ // convert external to internal key
+ Int_t nEmptySlots = 0;
+ const Int_t* bins = FindBins(externalKey, kTRUE, nEmptySlots);
+ if (!bins) return;
+
+ // check for empty slots
+ if (nEmptySlots > 0) {
+ AliError("incomplete key");
+ delete[] bins;
+ return;
+ }
+
+ // increment the corresponding counter
+ fCounters->AddBinContent(bins, (Double_t)value);
+
+ // clean memory
+ delete[] bins;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Print(const Option_t* opt) const
+{
+ /// Print every individual counters if opt=="", else call "Print(TString rubrics=opt, TString selections="")".
+
+ if (strcmp(opt,"")) {
+ const_cast<AliCounterCollection*>(this)->Print(opt, "");
+ return;
+ }
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ if (fCounters->GetNbins() == 0) {
+ printf("\nall counters are empty\n\n");
+ return;
+ }
+
+ Int_t nRubrics = fCounters->GetNdimensions();
+ Int_t* bins = new Int_t[nRubrics];
+
+ // loop over every filled counters
+ for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
+
+ // get the content of the bin
+ Int_t value = (Int_t) fCounters->GetBinContent(i, bins);
+
+ // build the corresponding counter name
+ TString counter;
+ for (Int_t j=0; j<nRubrics; j++) counter += Form("/%s",fCounters->GetAxis(j)->GetBinLabel(bins[j]));
+ counter += "/";
+
+ // print value
+ printf("\n%s %d", counter.Data(), value);
+ }
+ printf("\n\n");
+
+ // clean memory
+ delete[] bins;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintKeyWords() const
+{
+ /// Print the full list of key words.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ // loop over rubrics
+ Int_t nRubrics = fCounters->GetNdimensions();
+ for (Int_t iDim=0; iDim<nRubrics; iDim++) {
+ TAxis* axis = fCounters->GetAxis(iDim);
+
+ // print rubric's name
+ printf("\n%s:", axis->GetName());
+
+ // loop over key words
+ Bool_t first = kTRUE;
+ TObjString* label = 0x0;
+ TIter nextLabel(axis->GetLabels());
+ while ((label = static_cast<TObjString*>(nextLabel()))) {
+
+ //print key word's name
+ if (first) {
+ printf("%s", label->String().Data());
+ first = kFALSE;
+ } else printf(",%s", label->String().Data());
+
+ }
+ }
+ printf("\n\n");
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintValue(TString selections)
+{
+ /// Print value of selected counter.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ selections.ToUpper();
+
+ // convert external to internal key
+ Int_t nEmptySlots = 0;
+ const Int_t* selectedBins = FindBins(selections, kFALSE, nEmptySlots);
+ if (!selectedBins) return;
+
+ // check for empty slots
+ if (nEmptySlots > 0) {
+ AliError("incomplete key");
+ delete[] selectedBins;
+ return;
+ }
+
+ // print value
+ printf("\n%d\n\n", (Int_t) fCounters->GetBinContent(selectedBins));
+
+ // clean memory
+ delete[] selectedBins;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Print(TString rubrics, TString selections)
+{
+ /// Print desired rubrics for the given selection:
+ /// - format of "rubrics" is rubric1/rubric2/.. (order matters only for output).
+ /// - format of "selections" is rubric:keyWord/rubric:keyWord/.. (order does not matter).
+ /// If "data" contains 1 rubric, the output will be one counter for each element of that rubric.
+ /// If "data" contains 2 rubrics, the output will be an array of counters, rubric1 vs rubric2.
+ /// If "data" contains 3 rubrics, the output will be an array rubric1 vs rubric2 for each element in rubric3.
+ /// ...
+ /// Results are integrated over rubrics not specified neither in "rubrics" nor in "selections".
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ rubrics.ToUpper();
+ selections.ToUpper();
+
+ // get the rubrics to print
+ TObjArray* rubricsToPrint = rubrics.Tokenize("/");
+ if (rubricsToPrint->GetEntriesFast() == 0) {
+ delete rubricsToPrint;
+ return;
+ }
+
+ // remove rubrics called twice
+ CleanListOfStrings(rubricsToPrint);
+
+ // project counters in the rubrics to print according to the selections
+ TObject* hist = Projection(*rubricsToPrint, selections);
+ if (!hist) {
+ delete rubricsToPrint;
+ return;
+ }
+
+ // print counters
+ Int_t nRubricsToPrint = rubricsToPrint->GetEntriesFast();
+ if (nRubricsToPrint == 1 && (static_cast<TH1D*>(hist))->Integral() > 0.)
+ PrintList(static_cast<TH1D*>(hist));
+ else if (nRubricsToPrint == 2 && (static_cast<TH2D*>(hist))->Integral() > 0.)
+ PrintArray(static_cast<TH2D*>(hist));
+ else if (nRubricsToPrint > 2 && (static_cast<THnSparse*>(hist))->GetNbins() > 0)
+ PrintListOfArrays(static_cast<THnSparse*>(hist));
+ else
+ printf("\nselected counters are empty\n\n");
+
+ // clean memory
+ delete rubricsToPrint;
+ delete hist;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintSum(TString rubric, TString selections)
+{
+ /// Print the overall statistics under the given rubric for the given selection:
+ /// - format of "selections" is rubric:keyWord/rubric:keyWord/.. (order does not matter).
+ /// Result is integrated over rubrics not specified neither in "rubric" nor in "selections".
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ rubric.ToUpper();
+ selections.ToUpper();
+
+ // fill the rubric to sum
+ TObjArray rubricsToSum(1);
+ rubricsToSum.SetOwner();
+ rubricsToSum.AddLast(new TObjString(rubric.Data()));
+
+ // project counters in the rubric to sum according to the selections
+ TH1D* hist = static_cast<TH1D*>(Projection(rubricsToSum, selections));
+ if (!hist) return;
+
+ // check for empty rubric
+ THashList* labels = hist->GetXaxis()->GetLabels();
+ if (!labels) {
+ printf("\n0\n\n");
+ return;
+ }
+
+ // print the sum of counters under that rubric
+ TObjString* any = static_cast<TObjString*>(labels->FindObject("ANY"));
+ if (any) printf("\n%d\n\n", (Int_t) hist->GetBinContent((Int_t)any->GetUniqueID()));
+ else printf("\n%d\n\n", (Int_t) hist->Integral());
+
+ // clean memory
+ delete hist;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintList(const TH1D* hist) const
+{
+ /// Print the content of 1D histogram as a list.
+
+ // set the format to print labels
+ THashList* labels = hist->GetXaxis()->GetLabels();
+ TString format(Form("\n%%%ds %%9d",GetMaxLabelSize(labels)));
+
+ // print value for each label
+ TObjString* label = 0x0;
+ TIter nextLabel(labels);
+ while ((label = static_cast<TObjString*>(nextLabel()))) {
+ Int_t bin = (Int_t) label->GetUniqueID();
+ printf(format.Data(), label->String().Data(), (Int_t) hist->GetBinContent(bin));
+ }
+ printf("\n\n");
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintArray(const TH2D* hist) const
+{
+ /// Print the content of 2D histogram as an array.
+
+ // set the format to print labels in X direction
+ THashList* labelsX = hist->GetXaxis()->GetLabels();
+ TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
+
+ // set the format to print labels in Y direction and values
+ THashList* labelsY = hist->GetYaxis()->GetLabels();
+ Int_t maxLabelSizeY = TMath::Max(9, GetMaxLabelSize(labelsY));
+ TString formatYs(Form("%%%ds ",maxLabelSizeY));
+ TString formatYd(Form("%%%dd ",maxLabelSizeY));
+
+ // print labels in Y axis
+ printf(formatX.Data()," ");
+ TObjString* labelY = 0x0;
+ TIter nextLabelY(labelsY);
+ while ((labelY = static_cast<TObjString*>(nextLabelY())))
+ printf(formatYs.Data(), labelY->String().Data());
+
+ // fill array for each label in X axis
+ TObjString* labelX = 0x0;
+ TIter nextLabelX(labelsX);
+ while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
+ Int_t binX = (Int_t) labelX->GetUniqueID();
+
+ // print label X
+ printf(formatX.Data(), labelX->String().Data());
+
+ // print value for each label in Y axis
+ nextLabelY.Reset();
+ while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
+ Int_t binY = (Int_t) labelY->GetUniqueID();
+ printf(formatYd.Data(), (Int_t) hist->GetBinContent(binX, binY));
+ }
+ }
+ printf("\n\n");
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::PrintListOfArrays(const THnSparse* hist) const
+{
+ /// Print the content of nD histogram as a list of arrays.
+
+ // set the format to print labels in X direction
+ THashList* labelsX = hist->GetAxis(0)->GetLabels();
+ TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
+
+ // set the format to print labels in Y direction and values
+ THashList* labelsY = hist->GetAxis(1)->GetLabels();
+ Int_t maxLabelSizeY = TMath::Max(9, GetMaxLabelSize(labelsY));
+ TString formatYs(Form("%%%ds ",maxLabelSizeY));
+ TString formatYd(Form("%%%dd ",maxLabelSizeY));
+
+ // create a list containing each combination of labels refering the arrays to be printout
+ TList listOfCombis;
+ listOfCombis.SetOwner();
+
+ // add a first empty combination
+ Int_t nDim = hist->GetNdimensions();
+ listOfCombis.AddLast(new TObjArray(nDim-2));
+
+ // loop over the nDim-2 other rubrics
+ for (Int_t i=2; i<nDim; i++) {
+
+ // save the last label of that rubic
+ THashList* labels = hist->GetAxis(i)->GetLabels();
+ TObjString* lastLabel = (labels) ? static_cast<TObjString*>(labels->Last()) : 0x0;
+ if (!lastLabel) return;
+
+ // prepare iteration over the list of labels
+ TIter nextLabel(labels);
+
+ // loop over existing combinations
+ TObjLink* lnk = listOfCombis.FirstLink();
+ while (lnk) {
+
+ // get the current combination
+ TObjArray* currentCombi = static_cast<TObjArray*>(lnk->GetObject());
+
+ // loop over labels in the current rubric
+ nextLabel.Reset();
+ TObjString* label = 0x0;
+ while ((label = static_cast<TObjString*>(nextLabel()))) {
+
+ // stop at the last one
+ if (label == lastLabel) break;
+
+ // copy the current combination, add the current label to it and add it to the list of combinations
+ TObjArray* combi = new TObjArray(*currentCombi);
+ combi->AddLast(label);
+ listOfCombis.AddBefore(lnk, combi);
+ }
+
+ // add the last label to the current combination
+ currentCombi->AddLast(lastLabel);
+
+ lnk = lnk->Next();
+ }
+
+ }
+
+ // create bin coordinates to access individual counters
+ Int_t* bins = new Int_t[nDim];
+
+ // loop over each combination of labels
+ TObjArray* combi = 0x0;
+ TIter nextCombi(&listOfCombis);
+ while ((combi = static_cast<TObjArray*>(nextCombi()))) {
+
+ // make the name of the combination and fill the corresponding bin coordinates
+ TString combiName = "/";
+ for (Int_t i=2; i<nDim; i++) {
+ TObjString* label = static_cast<TObjString*>(combi->UncheckedAt(i-2));
+ combiName += Form("%s/",label->String().Data());
+ bins[i] = (Int_t)label->GetUniqueID();
+ }
+
+ // skip empty array
+ Bool_t empty = kTRUE;
+ TObjString* labelX = 0x0;
+ TObjString* labelY = 0x0;
+ TIter nextLabelX(labelsX);
+ TIter nextLabelY(labelsY);
+ while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
+ bins[0] = (Int_t) labelX->GetUniqueID();
+ nextLabelY.Reset();
+ while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
+ bins[1] = (Int_t) labelY->GetUniqueID();
+ if (((Int_t) hist->GetBinContent(bins)) > 0) {
+ empty = kFALSE;
+ break;
+ }
+ }
+ if (!empty) break;
+ }
+ if (empty) continue;
+
+ // print the name of the combination of labels refering the incoming array
+ printf("\n%s:\n",combiName.Data());
+
+ // print labels in Y axis
+ printf(formatX.Data()," ");
+ nextLabelY.Reset();
+ while ((labelY = static_cast<TObjString*>(nextLabelY())))
+ printf(formatYs.Data(), labelY->String().Data());
+
+ // fill array for each label in X axis
+ nextLabelX.Reset();
+ while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
+ bins[0] = (Int_t) labelX->GetUniqueID();
+
+ // print label X
+ printf(formatX.Data(), labelX->String().Data());
+
+ // print value for each label in Y axis
+ nextLabelY.Reset();
+ while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
+ bins[1] = (Int_t) labelY->GetUniqueID();
+ printf(formatYd.Data(), (Int_t) hist->GetBinContent(bins));
+ }
+ }
+ printf("\n\n");
+ }
+
+ // clean memory
+ delete[] bins;
+}
+
+//-----------------------------------------------------------------------
+Int_t AliCounterCollection::GetMaxLabelSize(THashList* labels) const
+{
+ /// Return the number of characters of the longest label.
+ Int_t maxLabelSize = 0;
+ TObjString* label = 0x0;
+ TIter nextLabel(labels);
+ while ((label = static_cast<TObjString*>(nextLabel())))
+ maxLabelSize = TMath::Max(maxLabelSize, label->String().Length());
+ return maxLabelSize;
+}
+
+//-----------------------------------------------------------------------
+TH1D* AliCounterCollection::Draw(TString rubric, TString selections)
+{
+ /// Draw counters of the rubric "rubric" for the given "selection".
+ /// Format of "selections" is rubric:keyWord/rubric:keyWord/.. (order does not matter).
+ /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections".
+ /// It is the responsability of the user to delete the returned histogram.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return 0x0;
+ }
+
+ rubric.ToUpper();
+ selections.ToUpper();
+
+ // fill the rubrics to print
+ TObjArray rubricsToPrint(1);
+ rubricsToPrint.SetOwner();
+ rubricsToPrint.AddLast(new TObjString(rubric.Data()));
+
+ // project counters in the rubrics to print according to the selections
+ TH1D* hist = static_cast<TH1D*>(Projection(rubricsToPrint, selections));
+
+ // draw counters
+ if (hist) {
+
+ // draw histogram
+ hist->Draw("htext");
+ hist->SetStats(kFALSE);
+
+ // set title
+ TString title = "Selections: ";
+ selections.Remove(TString::kBoth, '/');
+ if (selections.Length() > 0) title += Form("%s/", selections.Data());
+ TObject* rub = 0x0;
+ TIter nextRubric(fRubrics);
+ while ((rub = nextRubric())) {
+ if (selections.Contains(Form("%s:",rub->GetName()))) continue;
+ if (rubricsToPrint.Contains(rub->GetName())) continue;
+ title += Form("%s:ANY/", rub->GetName());
+ }
+ title.ReplaceAll("/", " ");
+ hist->SetTitle(title.Data());
+
+ // draw X axis
+ TAxis* axis = hist->GetXaxis();
+ THashList* labels = axis->GetLabels();
+ Int_t nLabels = (labels) ? labels->GetSize() : 1;
+ axis->SetRange(1,nLabels);
+ axis->SetNdivisions(1,kFALSE);
+ axis->SetTitle(rubric.Data());
+
+ // draw Y axis
+ hist->GetYaxis()->SetTitle("Counts");
+ }
+
+ return hist;
+}
+
+//-----------------------------------------------------------------------
+TH2D* AliCounterCollection::Draw(TString rubric1, TString rubric2, TString selections)
+{
+ /// Draw counters of the "rubric1" vs "rubric2" for the given "selection".
+ /// Format of "selections" is rubric:keyWord/rubric:keyWord/.. (order does not matter).
+ /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections".
+ /// It is the responsability of the user to delete the returned histogram.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return 0x0;
+ }
+
+ rubric1.ToUpper();
+ rubric2.ToUpper();
+ selections.ToUpper();
+
+ // fill the rubrics to print
+ TObjArray rubricsToPrint(2);
+ rubricsToPrint.SetOwner();
+ rubricsToPrint.AddLast(new TObjString(rubric2.Data()));
+ rubricsToPrint.AddLast(new TObjString(rubric1.Data()));
+
+ // project counters in the rubrics to print according to the selections
+ TH2D* hist = static_cast<TH2D*>(Projection(rubricsToPrint, selections));
+
+ // draw counters
+ if (hist) {
+
+ // draw histogram
+ hist->Draw("text");
+ hist->SetStats(kFALSE);
+
+ // set title
+ TString title = "Selections: ";
+ selections.Remove(TString::kBoth, '/');
+ if (selections.Length() > 0) title += Form("%s/", selections.Data());
+ TObject* rub = 0x0;
+ TIter nextRubric(fRubrics);
+ while ((rub = nextRubric())) {
+ if (selections.Contains(Form("%s:",rub->GetName()))) continue;
+ if (rubricsToPrint.Contains(rub->GetName())) continue;
+ title += Form("%s:ANY/", rub->GetName());
+ }
+ title.ReplaceAll("/", " ");
+ hist->SetTitle(title.Data());
+
+ // draw X axis
+ TAxis* axisX = hist->GetXaxis();
+ THashList* labelsX = axisX->GetLabels();
+ Int_t nLabelsX = (labelsX) ? labelsX->GetSize() : 1;
+ axisX->SetRange(1,nLabelsX);
+ axisX->SetNdivisions(1,kFALSE);
+ axisX->SetTitle(rubric2.Data());
+
+ // draw Y axis
+ TAxis* axisY = hist->GetYaxis();
+ THashList* labelsY = axisY->GetLabels();
+ Int_t nLabelsY = (labelsY) ? labelsY->GetSize() : 1;
+ axisY->SetRange(1,nLabelsY);
+ axisY->SetNdivisions(1,kFALSE);
+ axisY->SetTitle(rubric1.Data());
+ }
+
+ return hist;
+}
+
+//-----------------------------------------------------------------------
+TObject* AliCounterCollection::Projection(const TObjArray& data, const TString& selections)
+{
+ /// Return desired "data" for the given "selection" stored in a new histogram or 0x0 in case of failure.
+ /// The type of the histogram (TH1D, TH2D or THnSparse) depend on the number of data.
+ /// It is the responsability of the user to delete the returned histogram.
+
+ // get the corresponding dimensions
+ Int_t nTargetDim = data.GetEntriesFast();
+ Int_t* targetDims = new Int_t[nTargetDim];
+ for (Int_t i=0; i<nTargetDim; i++) {
+ targetDims[i] = FindDim(static_cast<TObjString*>(data.UncheckedAt(i))->String());
+ if (targetDims[i] < 0) {
+ delete[] targetDims;
+ return 0x0;
+ }
+ }
+
+ // find bins to select
+ Int_t nEmptySlots = 0;
+ const Int_t* selectedBins = FindBins(selections, kFALSE, nEmptySlots);
+ if (!selectedBins) {
+ delete[] targetDims;
+ return 0x0;
+ }
+
+ // apply selection for each rubric
+ Int_t nRubrics = fCounters->GetNdimensions();
+ for (Int_t iDim=0; iDim<nRubrics; iDim++) {
+ TAxis* axis = fCounters->GetAxis(iDim);
+
+ // select the desired key word
+ if (selectedBins[iDim] >= 0) axis->SetRange(selectedBins[iDim], selectedBins[iDim]);
+
+ // or select all key words
+ else if (data.Contains(axis->GetName())) axis->SetRange();
+
+ // or integrate over all cases
+ else {
+ THashList* labels = axis->GetLabels();
+ TObjString* label = (labels) ? static_cast<TObjString*>(labels->FindObject("ANY")) : 0x0;
+ Int_t binAny = (label) ? (Int_t)label->GetUniqueID() : -1;
+ if (binAny >= 0) axis->SetRange(binAny, binAny);
+ else axis->SetRange();
+ }
+ }
+
+ // do projection
+ TObject* hist = 0x0;
+ if (nTargetDim == 1) {
+
+ // project counters to TH1D
+ hist = fCounters->Projection(targetDims[0]);
+
+ // reset bin labels lost when producing TH1D
+ if (selectedBins[targetDims[0]] >= 0)
+ static_cast<TH1D*>(hist)->GetXaxis()->SetBinLabel(1, fCounters->GetAxis(targetDims[0])->GetBinLabel(selectedBins[targetDims[0]]));
+ else {
+ TObjString* label;
+ TIter nextLabel(fCounters->GetAxis(targetDims[0])->GetLabels());
+ while ((label = static_cast<TObjString*>(nextLabel())))
+ static_cast<TH1D*>(hist)->GetXaxis()->SetBinLabel((Int_t)label->GetUniqueID(), label->String().Data());
+ }
+
+ } else if (nTargetDim == 2) {
+
+ // project counters to TH2D (warning X and Y inverted in THnSparse::Projection(X,Y))
+ hist = fCounters->Projection(targetDims[1], targetDims[0]);
+
+ // reset bin labels in X axis lost when producing TH2D
+ if (selectedBins[targetDims[0]] >= 0)
+ static_cast<TH2D*>(hist)->GetXaxis()->SetBinLabel(1, fCounters->GetAxis(targetDims[0])->GetBinLabel(selectedBins[targetDims[0]]));
+ else {
+ TObjString* label;
+ TIter nextLabel(fCounters->GetAxis(targetDims[0])->GetLabels());
+ while ((label = static_cast<TObjString*>(nextLabel())))
+ static_cast<TH2D*>(hist)->GetXaxis()->SetBinLabel((Int_t)label->GetUniqueID(), label->String().Data());
+ }
+
+ // reset bin labels in Y axis lost when producing TH2D
+ if (selectedBins[targetDims[1]] >= 0)
+ static_cast<TH2D*>(hist)->GetYaxis()->SetBinLabel(1, fCounters->GetAxis(targetDims[1])->GetBinLabel(selectedBins[targetDims[1]]));
+ else {
+ TObjString* label;
+ TIter nextLabel(fCounters->GetAxis(targetDims[1])->GetLabels());
+ while ((label = static_cast<TObjString*>(nextLabel())))
+ static_cast<TH2D*>(hist)->GetYaxis()->SetBinLabel((Int_t)label->GetUniqueID(), label->String().Data());
+ }
+
+ } else {
+
+ // project counters to THnSparse (labels are not lost in that case)
+ hist = fCounters->Projection(nTargetDim, targetDims);
+
+ // reset bin labels in case only one bin has been selected
+ for (Int_t i=0; i<nTargetDim; i++) {
+ if (selectedBins[targetDims[i]] >= 0) {
+ TAxis* axis = static_cast<THnSparse*>(hist)->GetAxis(i);
+ axis->GetLabels()->Clear();
+ axis->SetBinLabel(1, fCounters->GetAxis(targetDims[i])->GetBinLabel(selectedBins[targetDims[i]]));
+ }
+ }
+
+ }
+
+ // clean memory
+ delete[] targetDims;
+ delete[] selectedBins;
+
+ return hist;
+}
+
+//-----------------------------------------------------------------------
+Int_t* AliCounterCollection::CheckConsistency(const AliCounterCollection* c)
+{
+ /// Consistency check of the two counter collections. To be consistent, both counters
+ /// must have the same rubrics with the same list of authorized key words if any.
+ /// Return the correspondence between the local rubric ordering and the one of the other counter,
+ /// or 0x0 in case of problem. It is the responsability of the user to delete the returned array.
+
+ if (!fCounters || !c->fCounters) {
+ AliError("counters are not initialized");
+ return 0x0;
+ }
+
+ // check if the number of rubrics is the same
+ Int_t nRubrics = fRubrics->GetSize();
+ if (c->fRubrics->GetSize() != nRubrics) {
+ AliError("both counters do not contain the same number of rubrics");
+ return 0x0;
+ }
+
+ Int_t* otherDims = new Int_t[nRubrics];
+
+ // loop over local rubrics
+ TObject* rubric1 = 0x0;
+ TIter nextRubric(fRubrics);
+ while ((rubric1 = nextRubric())) {
+
+ // find that rubric in the other counter
+ TObject* rubric2 = c->fRubrics->FindObject(rubric1->GetName());
+ if (!rubric2) {
+ AliError(Form("the other counter does not contain the rubric %s", rubric1->GetName()));
+ delete[] otherDims;
+ return 0x0;
+ }
+
+ // check the list of authorized key words if any
+ TObjArray* keyWords1 = dynamic_cast<TObjArray*>(rubric1);
+ TObjArray* keyWords2 = dynamic_cast<TObjArray*>(rubric2);
+ if (keyWords1 && keyWords2) {
+
+ // check if the number of key words is the same
+ if (keyWords1->GetEntriesFast() != keyWords2->GetEntriesFast()) {
+ AliError("that rubric does not contain the same number of authorized key words in both counters");
+ delete[] otherDims;
+ return 0x0;
+ }
+
+ // loop over local key words
+ TObjString* keyWord = 0x0;
+ TIter nextKeyWord(keyWords1);
+ while ((keyWord = static_cast<TObjString*>(nextKeyWord()))) {
+
+ // find that key word in the corresponding rubric of the other counter
+ if (!keyWords2->FindObject(keyWord->String().Data())) {
+ AliError(Form("rubric %s does not contain the key word %s in the other counter", rubric1->GetName(), keyWord->String().Data()));
+ delete[] otherDims;
+ return 0x0;
+ }
+
+ }
+
+ } else if (keyWords1 || keyWords2) {
+
+ // that rubric has not been initialized the same way in both counter
+ if (keyWords1) {
+ AliError(Form("rubric %s of the other counter does not contain a list of authorized key words while this does", rubric1->GetName()));
+ } else {
+ AliError(Form("rubric %s of this counter does not contain a list of authorized key words while the other does", rubric1->GetName()));
+ }
+ delete[] otherDims;
+ return 0x0;
+
+ }
+
+ // save the correspondence of rubric IDs in both counters
+ otherDims[rubric1->GetUniqueID()] = rubric2->GetUniqueID();
+
+ }
+
+ return otherDims;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Add(const AliCounterCollection* counter)
+{
+ /// Add the given AliCounterCollections to this. They must have the
+ /// same rubrics with the same list of authorized key words if any.
+
+ // check the consistency between the other counter and this and get the correspondences between rubric IDs.
+ Int_t* otherDims = CheckConsistency(counter);
+ if (!otherDims) return;
+
+ Int_t nRubrics = fCounters->GetNdimensions();
+ Int_t* thisBins = new Int_t[nRubrics];
+ Int_t* otherBins = new Int_t[nRubrics];
+
+ // loop over every filled bins inside the other counter
+ for (Long64_t i = 0; i < counter->fCounters->GetNbins(); i++) {
+
+ // get the content of the bin
+ Double_t value = counter->fCounters->GetBinContent(i, otherBins);
+
+ // convert "other" bin coordinates to "this" bin coordinates
+ Bool_t ok = kTRUE;
+ for (Int_t dim = 0; dim < nRubrics; dim++) {
+ TString label = counter->fCounters->GetAxis(otherDims[dim])->GetBinLabel(otherBins[otherDims[dim]]);
+ thisBins[dim] = FindBin(dim, label, kTRUE);
+ if (thisBins[dim] < 0) {
+ AliError("this counter is full, unable to add that key word");
+ ok = kFALSE;
+ break;
+ }
+ }
+ if (!ok) continue;
+
+ // increment the corresponding local counter
+ fCounters->AddBinContent(thisBins, value);
+ }
+
+ // clean memory
+ delete[] otherDims;
+ delete[] thisBins;
+ delete[] otherBins;
+}
+
+//-----------------------------------------------------------------------
+Long64_t AliCounterCollection::Merge(TCollection* list)
+{
+ /// Merge this with a list of AliCounterCollections. All AliCounterCollections provided
+ /// must have the same rubrics with the same list of authorized key words if any.
+
+ if (!list || !fCounters) return 0;
+ if (list->IsEmpty()) return (Long64_t)fCounters->GetEntries();
+
+ TIter next(list);
+ const TObject* obj = 0x0;
+ while ((obj = next())) {
+
+ // check that "obj" is an object of the class AliCounterCollection
+ const AliCounterCollection* counter = dynamic_cast<const AliCounterCollection*>(obj);
+ if (!counter) {
+ AliError(Form("object named %s is not AliCounterCollection! Skipping it.", counter->GetName()));
+ continue;
+ }
+
+ // merge counter to this one
+ Add(counter);
+
+ }
+
+ return (Long64_t)fCounters->GetEntries();
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Sort(Option_t* opt, Bool_t asInt)
+{
+ /// Sort rubrics defined without a list of authorized key words or all rubrics if opt=="all".
+ /// If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ Bool_t all = (!strcasecmp(opt, "all"));
+
+ Bool_t somethingToSort = kFALSE;
+ Int_t nRubrics = fRubrics->GetSize();
+ Bool_t* rubricsToSort = new Bool_t[nRubrics];
+ memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
+
+ // choose rubrics to sort
+ TObject* rubric = 0x0;
+ TIter nextRubric(fRubrics);
+ while ((rubric = nextRubric())) {
+
+ if (all || dynamic_cast<TObjString*>(rubric)) {
+
+ // check if something to sort
+ THashList* labels = fCounters->GetAxis((Int_t)rubric->GetUniqueID())->GetLabels();
+ if (!labels || labels->GetSize() < 2) continue;
+
+ // select that rubric
+ rubricsToSort[(Int_t)rubric->GetUniqueID()] = kTRUE;
+ somethingToSort = kTRUE;
+
+ }
+
+ }
+
+ // sort selected rubrics if any
+ if (somethingToSort) Sort(rubricsToSort, asInt);
+
+ // clean memory
+ delete[] rubricsToSort;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::SortRubric(TString rubric, Bool_t asInt)
+{
+ /// Sort only that rubric. If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
+
+ if (!fCounters) {
+ AliError("counters are not initialized");
+ return;
+ }
+
+ rubric.ToUpper();
+
+ // find the rubric to sort
+ Int_t dim = FindDim(rubric);
+ if (dim < 0) return;
+
+ // check if something to sort
+ THashList* labels = fCounters->GetAxis(dim)->GetLabels();
+ if (!labels || labels->GetSize() < 2) return;
+
+ // select that rubric
+ Int_t nRubrics = fRubrics->GetSize();
+ Bool_t* rubricsToSort = new Bool_t[nRubrics];
+ memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
+ rubricsToSort[dim] = kTRUE;
+
+ // sort it
+ Sort(rubricsToSort, asInt);
+
+ // clean memory
+ delete[] rubricsToSort;
+}
+
+//-----------------------------------------------------------------------
+void AliCounterCollection::Sort(const Bool_t* rubricsToSort, Bool_t asInt)
+{
+ /// Sort labels (alphabetically or as integer) in each rubric flagged in "rubricsToSort".
+
+ // create a new counter
+ THnSparse* oldCounters = fCounters;
+ Int_t nRubrics = fRubrics->GetSize();
+ fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0);
+ Int_t** newBins = new Int_t*[nRubrics];
+
+ // define the new axes
+ for (Int_t i=0; i<nRubrics; i++) {
+ TAxis* oldAxis = oldCounters->GetAxis(i);
+ TAxis* newAxis = fCounters->GetAxis(i);
+
+ // set the name of the new axis
+ newAxis->SetName(oldAxis->GetName());
+
+ // get old labels
+ THashList* oldLabels = oldAxis->GetLabels();
+ if (!oldLabels) continue;
+
+ // sort them if required
+ if (rubricsToSort[i]) {
+ if (asInt) { oldLabels = SortAsInt(oldLabels); }
+ else { oldLabels->Sort(); }
+ }
+
+ // set labels in the new axis and save the correspondence between new and old bins
+ newBins[i] = new Int_t[oldLabels->GetSize()+1];
+ TObjString* label = 0x0;
+ Int_t bin = 1;
+ TIter nextLabel(oldLabels);
+ while ((label = static_cast<TObjString*>(nextLabel()))) {
+ newAxis->SetBinLabel(bin, label->String().Data());
+ newBins[i][(Int_t)label->GetUniqueID()] = bin;
+ bin++;
+ }
+
+ // clean memory
+ if (rubricsToSort[i] && asInt) delete oldLabels;
+ }
+
+ // fill the new counters
+ Int_t* oldCoor = new Int_t[nRubrics];
+ Int_t* newCoor = new Int_t[nRubrics];
+ for (Long64_t i = 0; i < oldCounters->GetNbins(); i++) {
+ Double_t value = oldCounters->GetBinContent(i, oldCoor);
+ for (Int_t dim = 0; dim < nRubrics; dim++) newCoor[dim] = newBins[dim][oldCoor[dim]];
+ fCounters->AddBinContent(newCoor, value);
+ }
+
+ // clean memory
+ for (Int_t i=0; i<nRubrics; i++) delete[] newBins[i];
+ delete[] newBins;
+ delete[] oldCoor;
+ delete[] newCoor;
+ delete oldCounters;
+}
+
+//-----------------------------------------------------------------------
+THashList* AliCounterCollection::SortAsInt(const THashList* labels)
+{
+ /// Return a list (not owner) of labels sorted assuming they are integers.
+ /// It is the responsability of user to delete the returned list.
+
+ THashList* sortedLabels = new THashList(labels->GetSize());
+ TIter nextSortedLabel(sortedLabels);
+
+ // loop over labels
+ TObjString* label = 0x0;
+ TIter nextLabel(labels);
+ while ((label = static_cast<TObjString*>(nextLabel()))) {
+
+ // find where to add it
+ TObjString* sortedLabel = 0x0;
+ nextSortedLabel.Reset();
+ while ((sortedLabel = static_cast<TObjString*>(nextSortedLabel())) &&
+ (sortedLabel->String().Atoi() <= label->String().Atoi())) {}
+
+ // add it
+ if (sortedLabel) sortedLabels->AddBefore(sortedLabel, label);
+ else sortedLabels->AddLast(label);
+ }
+
+ return sortedLabels;
+}
+
--- /dev/null
+#ifndef ALICOUNTERCOLLECTION_H
+#define ALICOUNTERCOLLECTION_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/// \ingroup PWG3muon
+/// \class AliCounterCollection
+/// \brief generic class to handle a collection of counters
+// Author: Philippe Pillot
+
+#include <TNamed.h>
+
+class TString;
+class TObjArray;
+class THnSparse;
+class THashList;
+class TArrayI;
+class TH1D;
+class TH2D;
+class TCollection;
+
+class AliCounterCollection : public TNamed {
+public:
+
+ AliCounterCollection(const char* name = "counters");
+ virtual ~AliCounterCollection();
+
+ virtual void Clear(Option_t* = "");
+
+ // Add a new rubric with the complete list of related key words separated by "/"
+ void AddRubric(TString name, TString listOfKeyWords);
+ // Add a new rubric containing at maximum maxNKeyWords key words
+ void AddRubric(TString name, Int_t maxNKeyWords);
+ // Initialize the internal counters from the added rubrics
+ void Init();
+
+ // Add "value" to the counter referenced by "externalKey"
+ void Count(TString externalKey, Int_t value = 1);
+
+ // Print every individual counters if opt=="", else call "Print(TString rubrics=opt, TString selections="")"
+ virtual void Print(const Option_t* opt = "") const;
+ // Print the full list of key words
+ void PrintKeyWords() const;
+ // Print value of selected counter
+ void PrintValue(TString selections);
+ // Print desired rubrics for the given selection
+ void Print(TString rubrics, TString selections);
+ // Print the overall statistics under the given rubric for the given selection
+ void PrintSum(TString rubric, TString selections = "");
+
+ /// Overload TObject::Draw(Option_t*): Call "Draw(TString rubric1=opt, TString selections="")"
+ virtual void Draw(Option_t* opt = "") {Draw(opt, "");}
+ // Draw counters of the rubric "rubric1" for the given "selection"
+ TH1D* Draw(TString rubric1, TString selections);
+ // Draw counters of the "rubric1" vs "rubric2" for the given "selection"
+ TH2D* Draw(TString rubric1, TString rubric2, TString selections);
+
+ // Add the given AliCounterCollections to this
+ void Add(const AliCounterCollection* counter);
+
+ // Merge this with a list of AliCounterCollections
+ Long64_t Merge(TCollection* list);
+
+ // Sort rubrics defined without a list of authorized key words or all rubrics if opt=="all"
+ void Sort(Option_t* opt = "", Bool_t asInt = kFALSE);
+ /// Sort only that rubric. If asInt=kTRUE, key words are ordered as interger instead of alphabetically
+ void SortRubric(TString rubric, Bool_t asInt = kFALSE);
+
+private:
+
+ /// Not implemented
+ AliCounterCollection(const AliCounterCollection& rhs);
+ /// Not implemented
+ AliCounterCollection& operator = (const AliCounterCollection& rhs);
+
+ // Return the corresponding bins ordered by rubric or 0x0 if externalKey is not valid
+ const Int_t* FindBins(const TString& externalKey, Bool_t allocate, Int_t& nEmptySlots);
+ // Return the dimension corresponding to that rubric (or -1)
+ Int_t FindDim(const TString& rubricName) const;
+ // Return the bin number corresponding to that key word (or -1)
+ Int_t FindBin(Int_t dim, const TString& keyWord, Bool_t allocate);
+
+ // Make sure all strings appear only once in this list
+ void CleanListOfStrings(TObjArray* list);
+
+ // Print the content of 1D histogram as a list
+ void PrintList(const TH1D* hist) const;
+ // Print the content of 2D histogram as an array
+ void PrintArray(const TH2D* hist) const;
+ // Print the content of nD histogram as a list of arrays
+ void PrintListOfArrays(const THnSparse* hist) const;
+
+ // Return the number of characters of the longest label
+ Int_t GetMaxLabelSize(THashList* labels) const;
+
+ // Return desired "data" for the given "selection" stored in a new histogram or 0x0
+ TObject* Projection(const TObjArray& data, const TString& selections);
+
+ // Consistency check of the two counter collections
+ Int_t* CheckConsistency(const AliCounterCollection* c);
+
+ // Sort labels (alphabetically or as integer) in each rubric flagged in "rubricsToSort"
+ void Sort(const Bool_t* rubricsToSort, Bool_t asInt);
+ /// Return a list (not owner) of labels sorted assuming they are integers
+ THashList* SortAsInt(const THashList* labels);
+
+private:
+
+ THashList* fRubrics; ///< list of rubrics with associated key words
+ TArrayI* fRubricsSize; ///< maximum number of key words in the corresponding rubric
+ THnSparse* fCounters; ///< histogram of nRubrics dimensions used as n-dimensional counter
+
+ ClassDef(AliCounterCollection, 1); // collection of mergeable counters
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Base macro for submitting muon QA analysis.
+//
+// In case it is not run with full aliroot, it needs the following libraries:
+// - libSTEERBase.so
+// - libESD.so
+// - libAOD.so
+// - libANALYSIS.so
+// - libANALYSISalice.so
+// - libCORRFW.so
+// - libPWG3muon.so
+//
+// The macro reads ESDs and store outputs in standard output file (AnalysisResults.root)
+//
+// Author: Philippe Pillot - SUBATECH Nantes
+//--------------------------------------------------------------------------
+
+enum {kLocal, kInteractif_xml, kInteractif_ESDList};
+
+void RunMuonQA(TString inputFileName = "AliESDs.root", Bool_t selectPhysics = kTRUE, Short_t selectCharge = 0)
+{
+ TStopwatch timer;
+ timer.Start();
+
+ // Check runing mode
+ Int_t mode = GetMode(inputFileName);
+ if(mode < 0){
+ Error("RunMuonQA","Please provide either an ESD root file or a collection of ESDs.");
+ return;
+ }
+
+ // Load common libraries
+ gSystem->Load("libTree");
+ gSystem->Load("libGeom");
+ gSystem->Load("libVMC");
+ gSystem->Load("libPhysics");
+ gSystem->Load("libSTEERBase");
+ gSystem->Load("libESD");
+ gSystem->Load("libAOD");
+ gSystem->Load("libANALYSIS");
+ gSystem->Load("libANALYSISalice");
+ gSystem->Load("libCORRFW");
+ gSystem->Load("libPWG3muon");
+
+ // Create input chain
+ TChain* chain = CreateChain(inputFileName);
+ if (!chain) return;
+
+ // Create the analysis manager
+ AliAnalysisManager *mgr = new AliAnalysisManager("MuonQAAnalysis");
+
+ // ESD input handler
+ AliESDInputHandler* esdH = new AliESDInputHandler();
+ esdH->SetReadFriends(kFALSE);
+ mgr->SetInputEventHandler(esdH);
+
+ // event selection
+ gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
+ AliPhysicsSelectionTask* physicsSelection = AddTaskPhysicsSelection();
+ if(!physicsSelection) {
+ Error("RunMuonQA","AliPhysicsSelectionTask not created!");
+ return;
+ }
+
+ // Muon QA analysis
+ gROOT->LoadMacro("$ALICE_ROOT/PWG3/muon/AddTaskMuonQA.C");
+ AliAnalysisTaskMuonQA* muonQA = AddTaskMuonQA(selectPhysics, selectCharge);
+ if(!muonQA) {
+ Error("RunMuonQA","AliAnalysisTaskMuonQA not created!");
+ return;
+ }
+
+ // Enable debug printouts
+ //mgr->SetDebugLevel(2);
+
+ // start local analysis
+ if (mgr->InitAnalysis()) {
+ mgr->PrintStatus();
+ mgr->StartAnalysis("local", chain);
+ }
+
+ timer.Stop();
+ timer.Print();
+}
+
+//______________________________________________________________________________
+Int_t GetMode(TString inputFileName)
+{
+ if ( inputFileName.EndsWith(".xml") ) return kInteractif_xml;
+ else if ( inputFileName.EndsWith(".txt") ) return kInteractif_ESDList;
+ else if ( inputFileName.EndsWith(".root") ) return kLocal;
+ return -1;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromCollection(const char *xmlfile)
+{
+ // Create a chain from the collection of tags.
+ TAlienCollection* coll = TAlienCollection::Open(xmlfile);
+ if (!coll) {
+ ::Error("CreateChainFromTags", "Cannot create an AliEn collection from %s", xmlfile);
+ return NULL;
+ }
+
+ TGridResult* tagResult = coll->GetGridResult("",kFALSE,kFALSE);
+ AliTagAnalysis *tagAna = new AliTagAnalysis("ESD");
+ tagAna->ChainGridTags(tagResult);
+
+ AliRunTagCuts *runCuts = new AliRunTagCuts();
+ AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();
+ AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();
+ AliEventTagCuts *evCuts = new AliEventTagCuts();
+
+ // Check if the cuts configuration file was provided
+ if (!gSystem->AccessPathName("ConfigureCuts.C")) {
+ gROOT->LoadMacro("ConfigureCuts.C");
+ ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);
+ }
+
+ TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);
+ if (!chain || !chain->GetNtrees()) return NULL;
+ chain->ls();
+ return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromFile(const char *rootfile)
+{
+ // Create a chain using the root file.
+ TChain* chain = new TChain("esdTree");
+ chain->Add(rootfile);
+ if (!chain->GetNtrees()) return NULL;
+ chain->ls();
+ return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromESDList(const char *esdList)
+{
+ // Create a chain using tags from the run list.
+ TChain* chain = new TChain("esdTree");
+ ifstream inFile(esdList);
+ TString inFileName;
+ if (inFile.is_open()) {
+ while (! inFile.eof() ) {
+ inFileName.ReadLine(inFile,kFALSE);
+ if(!inFileName.EndsWith(".root")) continue;
+ chain->Add(inFileName.Data());
+ }
+ }
+ inFile.close();
+ if (!chain->GetNtrees()) return NULL;
+ chain->ls();
+ return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChain(TString inputFileName)
+{
+ printf("*******************************\n");
+ printf("*** Getting the Chain ***\n");
+ printf("*******************************\n");
+ Int_t mode = GetMode(inputFileName);
+ if(mode == kInteractif_xml) return CreateChainFromCollection(inputFileName.Data());
+ else if (mode == kInteractif_ESDList) return CreateChainFromESDList(inputFileName.Data());
+ else if (mode == kLocal) return CreateChainFromFile(inputFileName.Data());
+ else return NULL;
+}
+