Skip to content

Commit 1a03cba

Browse files
authored
[PWGCF] Added technical event cuts and QA histograms (#18615)
1 parent 762029b commit 1a03cba

1 file changed

Lines changed: 212 additions & 22 deletions

File tree

‎PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsDm.cxx‎

Lines changed: 212 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
// O2:
1717

18+
#include "Common/CCDB/EventSelectionParams.h"
1819
#include "Common/DataModel/Centrality.h"
1920
#include "Common/DataModel/EventSelection.h"
2021
#include "Common/DataModel/Multiplicity.h"
@@ -39,10 +40,12 @@
3940
#include <TH2.h>
4041
#include <TList.h>
4142
#include <TObject.h>
43+
#include <TProfile.h>
4244
#include <TString.h>
4345
#include <TSystem.h>
4446

4547
#include <array>
48+
#include <cmath>
4649
#include <cstdint>
4750
#include <string>
4851
#include <vector>
@@ -129,8 +132,17 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
129132

130133
Configurable<bool> cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"};
131134
Configurable<bool> cfFillQA{"cfFillQA", false, "book and fill QA histograms (only for development and validation)"}; // switch for QA histograms
135+
136+
// Define cuts:
132137
Configurable<bool> cfUseVertexZCut{"cfUseVertexZCut", true, "apply the vertex Z event cut"};
133138
Configurable<bool> cfUsePtCut{"cfUsePtCut", true, "apply the pt particle cut"};
139+
Configurable<bool> cfUseTimeRange{"cfUseTimeRange", true, "rejects events with overlapping collisions"};
140+
Configurable<bool> cfUseRof{"cfUseRof", true, "removes events containing multiple collisions in the same readout frame"};
141+
Configurable<bool> cfUsePileUp{"cfUsePileUp", true, "apply pile up cuts"};
142+
Configurable<bool> cfUseITSTPC{"cfUseITSTPC", true, "use reconstructed from the ITS (Inner Tracking System) and TPC (Time Porjection Chamber) tracks"};
143+
Configurable<bool> cfUseITSLayers{"cfUseITSLayers", true, "use the ITS layers cut"};
144+
Configurable<bool> cfUseZFT0vsPV{"cfUseZFT0vsPV", true, "use this cut"};
145+
Configurable<bool> cfUsePrevRof{"cfUsePrevRof", true, " use this cut"};
134146

135147
Configurable<std::string> cfCentralityEstimator{"cfCentralityEstimator", "FT0C", "centrality estimator: FT0C, FT0M, FT0A"}; // centrality estimator with valid values: FT0C (default)
136148
Configurable<std::string> cfReferenceMultiplicityEstimator{"cfReferenceMultiplicityEstimator", "FT0C", "reference multiplicity estimator: TPC, FT0C, FT0M"}; // ref. multiplicity estimator with valid values: TPC (default) FT0C Ft0M
@@ -147,14 +159,19 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
147159
Configurable<std::vector<float>> cfVertexXBins{"cfVertexXBins", {200, -1., 1.}, "nvxBins, vxMin, vxMax"};
148160
Configurable<std::vector<float>> cfVertexYBins{"cfVertexYBins", {200, -1, 1.}, "nvyBins, vyMin, vyMax"};
149161
Configurable<std::vector<float>> cfVertexZBins{"cfVertexZBins", {300, -15., 15.}, "nvzBins, vzMin, vzMax"};
162+
Configurable<std::vector<float>> cfNContribBins{"cfNContribBins", {500, 0., 5000.}, "nContribBins, contribMin, contribMax"};
150163
Configurable<std::vector<float>> cfVertexZ{"cfVertexZ", {-10., 10.}, "{min, max} [cm]"};
151164
Configurable<std::vector<float>> cfPt{"cfPt", {0.2, 5.0}, "{min, max} [GeV]"};
165+
Configurable<bool> cfUseEtaCut{"cfUseEtaCut", true, "apply the eta particle cut (pseudorapidity"};
166+
Configurable<std::vector<float>> cfEta{"cfEta", {-0.8, 0.8}, "eta range: {min, max}, with convention: min <= eta < max"};
152167

153168
// for weights (efficiency corrections)
154-
Configurable<bool> cfUseWeights{"cfUseWeights", false, "load weights from the file in cfFileWithWeights"};
169+
Configurable<bool> cfUsePhiWeights{"cfUsePhiWeights", false, "use phi weights from the file in cfFileWithWeights"};
170+
Configurable<bool> cfUsePtWeights{"cfUsePtWeights", false, "use pt weights from the file in cfFileWithWeights"};
171+
Configurable<bool> cfUseEtaWeights{"cfUseEtaWeights", false, "use eta weights from the file in cfFileWithWeights"};
155172
Configurable<std::string> cfFileWithWeights{"cfFileWithWeights", "", "path to external ROOT file with weights; on Hyperloop only CCDB paths (/alice-ccdb.cern.ch/...) work"};
156173

157-
Configurable<bool> cfVerbose{"cfVerbose", false, "print \run number, centrality and vertex for each collision"};
174+
Configurable<bool> cfVerbose{"cfVerbose", false, "print run number, centrality and vertex for each collision"};
158175

159176
// *) Define and initialize all data members to be called in the main process* functions:
160177
// **) Task configuration:
@@ -164,16 +181,27 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
164181
bool fFillQA = false; // book and fill QA histos
165182
bool fUseVertexZCut = true;
166183
bool fUsePtCut = true;
184+
bool fUseTimeRange = true;
185+
bool fUseRof = true;
186+
bool fUsePileUp = true;
187+
bool fUseITSTPC = true;
188+
bool fUseITSLayers = true;
189+
bool fUseZFT0vsPV = true;
190+
bool fUsePrevRof = true;
167191

168192
int fCentralityEstimator = ECentFT0C;
169193
int fReferenceMultiplicityEstimator = ERefMultTPC;
170194

171195
float fSigmaInel = 771.; // sigma inel [fm^2]
172196
std::array<float, 2> fVertexZ = {-10., 10.}; // {min, max} [cm]
173197
std::array<float, 2> fPt = {0.2, 5.0}; // {min, max} [GeV]
174-
bool fWeightsLoaded = false; // weights are loaded once, at the first collision
175-
bool fUseWeights = false; // load weights from external file
176-
bool fVerbose = false; // print the values / collision
198+
bool fUseEtaCut = true;
199+
std::array<float, 2> fEta = {-0.8, 0.8}; // {min, max}
200+
int fCurrentRunNumber = -1; // run number of the weights currently in use
201+
bool fUsePhiWeights = false; // load phi weights
202+
bool fUsePtWeights = false; // load pt weights
203+
bool fUseEtaWeights = false; // load eta weights
204+
bool fVerbose = false; // print the values / collision
177205

178206
} tc; // you have to prepend "tc." for all objects name in this group later in the code
179207

@@ -197,11 +225,20 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
197225

198226
struct QAHistograms {
199227
TList* fQAHistogramsList = nullptr;
200-
TH2F* fHistCentralityRecVsSim = nullptr; // x = centrality sim (from impact parameter), y = centrality rec
201-
} qa; // you have to prepend "qa." for all objects name in this group later in the code
228+
TH2F* fHistCentralityRecVsSim = nullptr; // x = centrality sim (from impact parameter), y = centrality rec
229+
std::array<TH2F*, EBeforeAfter_N> fHistRefMultVsNContrib{}; // x = reference multiplicity, y = number of vertex contributors [before, after]
230+
} qa; // you have to prepend "qa." for all objects name in this group later in the code
231+
232+
// **) Correlations:
233+
struct Correlations {
234+
TList* fCorrelationsList = nullptr;
235+
TProfile* fProfTwo = nullptr; // <<2>> = v2{2}^2 vs. centrality (rec)
236+
} cc;
202237

203238
// **) Histogram with weights from an external file
204-
TH1F* histWeights = nullptr;
239+
TH1F* histPhiWeights = nullptr; // phi weights for the current run
240+
TH1F* histPtWeights = nullptr; // pt weights for the current run
241+
TH1F* histEtaWeights = nullptr; // eta weights for the current run
205242

206243
// *) Define all member functions to be called in the main process* functions:
207244

@@ -291,8 +328,7 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
291328
return nullptr;
292329

293330
} // TObject* getObjectFromList(...)
294-
295-
TH1F* getHistogramWithWeights(const char* filePath, const char* runNumber)
331+
TH1F* getHistogramWithWeights(const char* filePath, const char* runNumber, const char* histName)
296332
{
297333
// Last update: 20261018
298334

@@ -427,7 +463,7 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
427463
// listWithRuns->ls();
428464

429465
// get pointer to "hist" from "listWithRuns"
430-
hist = dynamic_cast<TH1F*>(getObjectFromList(listWithRuns, "histWithEfficiencyCorrections_1"));
466+
hist = dynamic_cast<TH1F*>(getObjectFromList(listWithRuns, histName));
431467
if (!hist) {
432468
LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__);
433469
}
@@ -443,6 +479,36 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
443479

444480
} // end of TH1F* getHistogramWithWeights(...)
445481

482+
// load one kind of weights for this run (or reuse it if already loaded), and save it in the output
483+
TH1F* loadWeights(const char* nameInFile, const char* nameInOutput, int runNumber)
484+
{
485+
TString name = Form("%s_%d", nameInOutput, runNumber);
486+
TH1F* hist = dynamic_cast<TH1F*>(fBaseList->FindObject(name.Data()));
487+
if (!hist) {
488+
hist = getHistogramWithWeights(cfFileWithWeights.value.c_str(), Form("%d", runNumber), nameInFile);
489+
hist->SetName(name.Data()); // e.g. histPhiWeights_544116
490+
hist->SetTitle(cfFileWithWeights.value.c_str()); // book-keeping: title = file path
491+
fBaseList->Add(hist); // saved in AnalysisResults.root
492+
}
493+
return hist;
494+
}
495+
496+
// weight of one particle: product of all enabled weights, 1 if none is enabled
497+
float getParticleWeight(float phi, float pt, float eta)
498+
{
499+
float weight = 1.;
500+
if (tc.fUsePhiWeights && histPhiWeights) {
501+
weight *= histPhiWeights->GetBinContent(histPhiWeights->FindBin(phi));
502+
}
503+
if (tc.fUsePtWeights && histPtWeights) {
504+
weight *= histPtWeights->GetBinContent(histPtWeights->FindBin(pt));
505+
}
506+
if (tc.fUseEtaWeights && histEtaWeights) {
507+
weight *= histEtaWeights->GetBinContent(histEtaWeights->FindBin(eta));
508+
}
509+
return weight;
510+
}
511+
446512
//__ EVENT CUTS __
447513
template <ERecSim rs, typename T1>
448514
bool eventCuts(T1 const& collision)
@@ -454,6 +520,55 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
454520
return false; // if at least one event cut is not satisfied
455521
}
456522
}
523+
// *) No collision in time range cut
524+
if (tc.fUseTimeRange) {
525+
if (!collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) {
526+
return false; // if at least one event cut is not satisfied
527+
}
528+
}
529+
530+
// *) No collision in the same readout frame cut
531+
if (tc.fUseRof) {
532+
if (!collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) {
533+
return false; // if at least one event cut is not satisfied
534+
}
535+
}
536+
537+
// *) No same-bunch pile-up cut
538+
if (tc.fUsePileUp) {
539+
if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) {
540+
return false; // if at least one event cut is not satisfied
541+
}
542+
}
543+
544+
// *) Vertex from ITS and TPC tracks cut
545+
if (tc.fUseITSTPC) {
546+
if (!collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) {
547+
return false; // if at least one event cut is not satisfied
548+
}
549+
}
550+
551+
// *) All ITS layers good cut
552+
if (tc.fUseITSLayers) {
553+
if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) {
554+
return false; // if at least one event cut is not satisfied
555+
}
556+
}
557+
558+
// *) z vertex from FT0 and from tracks agree cut
559+
if (tc.fUseZFT0vsPV) {
560+
if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) {
561+
return false; // if at least one event cut is not satisfied
562+
}
563+
}
564+
565+
// *) No high-multiplicity collision in previous readout frame cut
566+
if (tc.fUsePrevRof) {
567+
if (!collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) {
568+
return false; // if at least one event cut is not satisfied
569+
}
570+
}
571+
457572
return true; // all event cuts passed
458573
}
459574

@@ -469,6 +584,13 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
469584
}
470585
}
471586

587+
// *) eta cut
588+
if (tc.fUseEtaCut) {
589+
if (!(tc.fEta[0] <= track.eta() && track.eta() < tc.fEta[1])) {
590+
return false; // if at least one particle cut is not satisfied
591+
}
592+
}
593+
472594
return true; // all particle cuts passed
473595
}
474596

@@ -488,6 +610,11 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
488610
ec.fEventHistograms[EVertexY][ERec][ba]->Fill(collision.posY());
489611
ec.fEventHistograms[EVertexZ][ERec][ba]->Fill(collision.posZ());
490612

613+
// QA: reference multiplicity vs. number of contributors
614+
if (tc.fFillQA) {
615+
qa.fHistRefMultVsNContrib[ba]->Fill(getReferenceMultiplicity(collision), collision.numContrib());
616+
}
617+
491618
if constexpr (rs == ERecAndSim) {
492619
if (!collision.has_mcCollision()) {
493620
LOGF(debug, " No MC collision for this collision, skip simulated part...");
@@ -529,14 +656,19 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
529656
return;
530657
}
531658

532-
// Load the weights once, at the first collision, because the run number is only known here
533-
if (tc.fUseWeights && !tc.fWeightsLoaded) {
534-
histWeights = getHistogramWithWeights(cfFileWithWeights.value.c_str(), Form("%d", collision.bc().runNumber()));
535-
histWeights->SetTitle(cfFileWithWeights.value.c_str()); // book-keeping: title = file path
536-
// value takes the text as std::string and c_str makes it into a constant char*
537-
538-
fBaseList->Add(histWeights); // so it is saved in AnalysisResults.root
539-
tc.fWeightsLoaded = true;
659+
// weights are run-specific: load them again when the run number changes
660+
int runNumber = collision.bc().runNumber();
661+
if (runNumber != tc.fCurrentRunNumber) {
662+
if (tc.fUsePhiWeights) {
663+
histPhiWeights = loadWeights("histWithEfficiencyCorrections_1", "histPhiWeights", runNumber);
664+
}
665+
if (tc.fUsePtWeights) {
666+
histPtWeights = loadWeights("histWithEfficiencyCorrections_2", "histPtWeights", runNumber);
667+
}
668+
if (tc.fUseEtaWeights) {
669+
histEtaWeights = loadWeights("histWithEfficiencyCorrections_3", "histEtaWeights", runNumber);
670+
}
671+
tc.fCurrentRunNumber = runNumber;
540672
}
541673

542674
// Print info for each collision, only if switched on in the config:
@@ -555,6 +687,9 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
555687
}
556688

557689
// Main loop over particles:
690+
// Q-vector of harmonic 2 and sums of weights, for <2> of this event
691+
double q2Re = 0., q2Im = 0., sumW = 0., sumW2 = 0.;
692+
558693
auto track = tracks.iteratorAt(0); // set the type and scope from one instance
559694
for (int64_t i = 0; i < tracks.size(); i++) {
560695

@@ -594,6 +729,13 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
594729
pc.fParticleHistograms[EPt][ERec][EAfter]->Fill(track.pt());
595730
pc.fParticleHistograms[EPhi][ERec][EAfter]->Fill(track.phi());
596731

732+
// add this particle to the Q-vector
733+
const double w = getParticleWeight(track.phi(), track.pt(), track.eta());
734+
q2Re += w * std::cos(2. * track.phi());
735+
q2Im += w * std::sin(2. * track.phi());
736+
sumW += w;
737+
sumW2 += w * w;
738+
597739
if constexpr (rs == ERecAndSim) {
598740
if (!track.has_mcParticle()) {
599741
continue;
@@ -610,6 +752,15 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
610752
} // end of for (int64_t i = 0; i < tracks.size(); i++) {
611753

612754
// Fill event histograms after event and particle cuts
755+
// <2> of this event, filled vs. centrality with event weight sumW^2 - sumW2 (= M(M-1) for unit weights)
756+
if constexpr (rs == ERec || rs == ERecAndSim) {
757+
const double denominator = sumW * sumW - sumW2;
758+
if (denominator > 0.) {
759+
const double two = (q2Re * q2Re + q2Im * q2Im - sumW2) / denominator;
760+
cc.fProfTwo->Fill(getCentrality(collision), two, denominator);
761+
}
762+
}
763+
613764
fillEventHistograms<rs>(collision, tracks, EAfter);
614765

615766
} // end of template <ERecSim rs, typename T1, typename T2> void steer(T1 const& collision, T2 const& tracks) {
@@ -631,9 +782,11 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
631782
tc.fVerbose = cfVerbose;
632783
tc.fSigmaInel = cfSigmaInel;
633784

634-
tc.fUseWeights = cfUseWeights;
635-
if (tc.fUseWeights && cfFileWithWeights.value.empty()) {
636-
LOGF(fatal, "cfUseWeights is true, but cfFileWithWeights is empty");
785+
tc.fUsePhiWeights = cfUsePhiWeights;
786+
tc.fUsePtWeights = cfUsePtWeights;
787+
tc.fUseEtaWeights = cfUseEtaWeights;
788+
if ((tc.fUsePhiWeights || tc.fUsePtWeights || tc.fUseEtaWeights) && cfFileWithWeights.value.empty()) {
789+
LOGF(fatal, "weights are switched on, but cfFileWithWeights is empty");
637790
}
638791

639792
// vertex Z cut copy the swtich and range
@@ -650,6 +803,22 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
650803
tc.fPt[0] = lPtCut[0];
651804
tc.fPt[1] = lPtCut[1];
652805

806+
// eta cut copy switch and range
807+
tc.fUseEtaCut = cfUseEtaCut;
808+
std::vector<float> lEtaCut = cfEta.value;
809+
810+
tc.fEta[0] = lEtaCut[0];
811+
tc.fEta[1] = lEtaCut[1];
812+
813+
// technical event cuts: copy the switches
814+
tc.fUseTimeRange = cfUseTimeRange;
815+
tc.fUseRof = cfUseRof;
816+
tc.fUsePileUp = cfUsePileUp;
817+
tc.fUseITSTPC = cfUseITSTPC;
818+
tc.fUseITSLayers = cfUseITSLayers;
819+
tc.fUseZFT0vsPV = cfUseZFT0vsPV;
820+
tc.fUsePrevRof = cfUsePrevRof;
821+
653822
// translate the centrality estimator string into the enum
654823
if (cfCentralityEstimator.value == "FT0C") {
655824
tc.fCentralityEstimator = ECentFT0C;
@@ -688,6 +857,18 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
688857
ec.fEventHistogramsList->SetOwner(true);
689858
fBaseList->Add(ec.fEventHistogramsList); // any nested TList in the base TList appears as a subdir in the output ROOT file
690859

860+
// correlations: <<2>> vs. centrality, in the centrality classes of the reference paper
861+
cc.fCorrelationsList = new TList();
862+
cc.fCorrelationsList->SetName("Correlations");
863+
cc.fCorrelationsList->SetOwner(true);
864+
fBaseList->Add(cc.fCorrelationsList);
865+
const std::array<double, 10> centBoundaries = {0., 5., 10., 20., 30., 40., 50., 60., 70., 80.};
866+
cc.fProfTwo = new TProfile("fProfTwo", "<<2>> = v_{2}{2}^{2} vs. centrality", centBoundaries.size() - 1, centBoundaries.data());
867+
cc.fProfTwo->GetXaxis()->SetTitle("centrality (%)");
868+
cc.fProfTwo->GetYaxis()->SetTitle("#LT#LT2#GT#GT");
869+
cc.fProfTwo->Sumw2();
870+
cc.fCorrelationsList->Add(cc.fProfTwo);
871+
691872
if (tc.fFillQA) { // only if QA switched on
692873
qa.fQAHistogramsList = new TList();
693874
qa.fQAHistogramsList->SetName("QA");
@@ -824,6 +1005,15 @@ struct MultiparticleCorrelationsDm { // this name is used in lower-case format t
8241005
qa.fHistCentralityRecVsSim->GetXaxis()->SetTitle("centrality simulated (%)");
8251006
qa.fHistCentralityRecVsSim->GetYaxis()->SetTitle("centrality reconstructed (%)");
8261007
qa.fQAHistogramsList->Add(qa.fHistCentralityRecVsSim);
1008+
1009+
// reference multiplicity vs. number of contributors, before and after cuts
1010+
std::vector<float> lContribBins = cfNContribBins.value;
1011+
for (int ba = 0; ba < EBeforeAfter_N; ba++) {
1012+
qa.fHistRefMultVsNContrib[ba] = new TH2F(Form("fHistRefMultVsNContrib[%s]", baNames[ba]), Form("reference multiplicity vs. number of contributors (%s cuts)", baNames[ba]), nRefMultBins, refMultMin, refMultMax, static_cast<int>(lContribBins[0]), lContribBins[1], lContribBins[2]);
1013+
qa.fHistRefMultVsNContrib[ba]->GetXaxis()->SetTitle("reference multiplicity");
1014+
qa.fHistRefMultVsNContrib[ba]->GetYaxis()->SetTitle("number of contributors");
1015+
qa.fQAHistogramsList->Add(qa.fHistRefMultVsNContrib[ba]);
1016+
}
8271017
}
8281018

8291019
} // end of void init(InitContext&) {

0 commit comments

Comments
 (0)