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"
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 \ r un 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