Skip to content

Commit 9d2aef2

Browse files
authored
support for randomization via Fisher-Yates algorithm (#4360)
1 parent 983e899 commit 9d2aef2

3 files changed

Lines changed: 88 additions & 13 deletions

File tree

PWGCF/MultiparticleCorrelations/Core/MuPa-DataMembers.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct TaskConfiguration {
5656
TString fWhatToProcess = "Rec"; // "Rec" = process only reconstructed, "Sim" = process only simulated, "RecSim" = process both reconstructed and simulated
5757
UInt_t fRandomSeed = 0; // argument to TRandom3 constructor. By default it is 0 (i.e. seed is guaranteed to be unique in time and space), use SetRandomSeed(...) to change it
5858
Bool_t fUseFisherYates = kFALSE; // algorithm used to randomize particle indices, set via configurable
59+
TArrayI* fRandomIndices = NULL; // array to store random indices obtained from Fisher-Yates algorithm
5960
Int_t fFixedNumberOfRandomlySelectedTracks = -1; // use a fixed number of randomly selected particles in each event. It is set and applied, if > 0. Set to <=0 to ignore.
6061

6162
// Bool_t fRescaleWithTheoreticalInput; // if kTRUE, all measured correlators are
@@ -126,7 +127,7 @@ Bool_t fCalculateCorrelations =
126127
struct Correlations_Arrays {
127128
TProfile* fCorrelationsPro[4][gMaxHarmonic][eAsFunctionOf_N] = {
128129
{{NULL}}}; //! multiparticle correlations
129-
//! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=6][0=integrated,1=vs.
130+
//! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=gMaxHarmonic][0=integrated,1=vs.
130131
//! multiplicity,2=vs. centrality,3=pT,4=eta]
131132
} c_a;
132133

@@ -151,9 +152,9 @@ Bool_t fCalculateNestedLoops = kTRUE; // calculate and store correlations with
151152
Bool_t fCalculateCustomNestedLoop =
152153
kFALSE; // validate e-b-e all correlations with custom nested loop
153154
struct NestedLoops_Arrays {
154-
TProfile* fNestedLoopsPro[4][6][eAsFunctionOf_N] = {
155+
TProfile* fNestedLoopsPro[4][gMaxHarmonic][eAsFunctionOf_N] = {
155156
{{NULL}}}; //! multiparticle correlations from nested loops
156-
//! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=6][0=integrated,1=vs.
157+
//! [2p=0,4p=1,6p=2,8p=3][n=1,n=2,...,n=gMaxHarmonic][0=integrated,1=vs.
157158
//! multiplicity,2=vs. centrality,3=pT,4=eta]
158159
TArrayD* ftaNestedLoops[2] = {NULL}; //! e-b-e container for nested loops
159160
//! [0=angles;1=product of all weights]

PWGCF/MultiparticleCorrelations/Core/MuPa-GlobalConstants.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#define PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_GLOBALCONSTANTS_H_
1414

1515
const Int_t gMaxCorrelator = 12;
16-
const Int_t gMaxHarmonic = 6;
16+
const Int_t gMaxHarmonic = 9;
1717
const Int_t gMaxIndex = 300; // per order, used only in Test0
1818

1919
#endif // PWGCF_MULTIPARTICLECORRELATIONS_CORE_MUPA_GLOBALCONSTANTS_H_

PWGCF/MultiparticleCorrelations/Core/MuPa-MemberFunctions.h

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void BookBaseList()
3939
Form("fTaskName = %s", tc.fTaskName.Data()));
4040

4141
fBasePro->GetXaxis()->SetBinLabel(eRunNumber,
42-
Form("tc.fRunNumber = %s", tc.fRunNumber.Data()));
42+
Form("fRunNumber = %s", tc.fRunNumber.Data()));
4343

4444
fBasePro->GetXaxis()->SetBinLabel(eVerbose, "fVerbose");
4545
fBasePro->Fill(eVerbose - 0.5, (Int_t)tc.fVerbose);
@@ -57,7 +57,7 @@ void BookBaseList()
5757
fBasePro->Fill(eProcessRemainingEvents - 0.5, (Int_t)tc.fProcessRemainingEvents);
5858

5959
fBasePro->GetXaxis()->SetBinLabel(eWhatToProcess,
60-
Form("tc.WhatToProcess = %s", tc.fWhatToProcess.Data()));
60+
Form("WhatToProcess = %s", tc.fWhatToProcess.Data()));
6161

6262
fBasePro->GetXaxis()->SetBinLabel(eRandomSeed, "fRandomSeed");
6363
fBasePro->Fill(eRandomSeed - 0.5, (Int_t)tc.fRandomSeed);
@@ -126,6 +126,10 @@ void DefaultConfiguration()
126126
// identical to the internal definitions in MuPa-Configurables.h, the
127127
// settings in json file are silently ignored.
128128

129+
// c) Scientific notation is NOT supported in json file. E.g. if you have
130+
// "cSelectedTracks_max": "1e3",
131+
// that setting and ALL other ones in json are silently ignored.
132+
129133
if (tc.fVerbose) {
130134
LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__);
131135
}
@@ -1010,7 +1014,7 @@ void BookTest0Histograms()
10101014

10111015
// a) Book the profile holding flags;
10121016
// b) Book placeholder and make sure all labels are stored in the placeholder;
1013-
// c) Retreive labels from placeholder;
1017+
// c) Retrieve labels from placeholder;
10141018
// d) Book what needs to be booked;
10151019
// e) Few quick insanity checks on booking.
10161020

@@ -1036,7 +1040,7 @@ void BookTest0Histograms()
10361040
fTest0List->Add(fTest0LabelsPlaceholder);
10371041
}
10381042

1039-
// c) Retreive labels from placeholder:
1043+
// c) Retrieve labels from placeholder:
10401044
if (!(this->RetrieveCorrelationsLabels())) {
10411045
LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m",
10421046
__PRETTY_FUNCTION__, __LINE__);
@@ -1221,7 +1225,7 @@ void ResetEventByEventQuantities()
12211225
fSelectedTracks = 0;
12221226
fCentrality = 0;
12231227

1224-
// c) Q-vectors:
1228+
// b) Q-vectors:
12251229
if (fCalculateQvector) {
12261230
ResetQ(); // generic Q-vector
12271231
for (Int_t h = 0; h < gMaxHarmonic * gMaxCorrelator + 1; h++) {
@@ -1232,7 +1236,7 @@ void ResetEventByEventQuantities()
12321236
}
12331237
} // if(fCalculateQvector)
12341238

1235-
// d) Reset ebe containers for nested loops:
1239+
// c) Reset ebe containers for nested loops:
12361240
if (fCalculateNestedLoops || fCalculateCustomNestedLoop) {
12371241
if (nl_a.ftaNestedLoops[0]) {
12381242
nl_a.ftaNestedLoops[0]->Reset();
@@ -1246,7 +1250,13 @@ void ResetEventByEventQuantities()
12461250

12471251
} // if(fCalculateNestedLoops||fCalculateCustomNestedLoop)
12481252

1249-
// ... TBI 20220809 port the rest ...
1253+
// d) Fisher-Yates algorithm:
1254+
if (tc.fUseFisherYates) {
1255+
delete tc.fRandomIndices;
1256+
tc.fRandomIndices = NULL;
1257+
}
1258+
1259+
// ... TBI 20240117 port the rest ...
12501260

12511261
} // void ResetEventByEventQuantities()
12521262

@@ -2930,7 +2940,8 @@ void StoreLabelsInPlaceholder()
29302940
// a) Initialize all counters;
29312941
// b) Fetch TObjArray with labels from an external file;
29322942
// c) Book the placeholder fTest0LabelsPlaceholder for all labels;
2933-
// d) Finally, store the labels from external source into placeholder.
2943+
// d) Finally, store the labels from external source into placeholder;
2944+
// e) Insantity check on labels.
29342945

29352946
if (tc.fVerbose) {
29362947
LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__);
@@ -2985,6 +2996,19 @@ void StoreLabelsInPlaceholder()
29852996
// cout<<oa->GetEntries()<<endl;
29862997
} // for(Int_t e=0; e<nLabels; e++)
29872998

2999+
// e) Insantity check on labels:
3000+
// Here I am merely checking that harmonic larget than gMaxHarmonic was not requested.
3001+
for (Int_t b = 1; b <= fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); b++) {
3002+
TObjArray* temp = TString(fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b)).Tokenize(" ");
3003+
for (Int_t h = 0; h < temp->GetEntries(); h++) {
3004+
if (TMath::Abs(TString(temp->At(h)->GetName()).Atoi()) > gMaxHarmonic) {
3005+
LOGF(info, "\033[1;31m bin = %d, label = %s, gMaxHarmonic = %d\033[0m", b, fTest0LabelsPlaceholder->GetXaxis()->GetBinLabel(b), (Int_t)gMaxHarmonic);
3006+
LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__);
3007+
} // if(TString(temp->At(h)->GetName()).Atoi() > gMaxHarmonic) {
3008+
} // for(Int_t h = 0; h < temp->GetEntries(); h++) {
3009+
delete temp; // yes, otherwise it's a memory leak
3010+
} // for(Int_t b = 1; b <= fTest0LabelsPlaceholder->GetXaxis()->GetNbins(); b++) {
3011+
29883012
} // void StoreLabelsInPlaceholder()
29893013

29903014
//============================================================
@@ -3426,6 +3450,35 @@ void DetermineCentrality()
34263450

34273451
//============================================================
34283452

3453+
void RandomIndices(Int_t nTracks)
3454+
{
3455+
// Randomize indices using Fisher-Yates algorithm.
3456+
3457+
if (tc.fVerbose) {
3458+
LOGF(info, "\033[1;32m%s\033[0m", __PRETTY_FUNCTION__);
3459+
}
3460+
3461+
if (nTracks < 1) {
3462+
return;
3463+
}
3464+
3465+
// Fisher-Yates algorithm:
3466+
tc.fRandomIndices = new TArrayI(nTracks);
3467+
tc.fRandomIndices->Reset(); // just in case there is some random garbage in memory at init
3468+
for (Int_t i = 0; i < nTracks; i++) {
3469+
tc.fRandomIndices->AddAt(i, i);
3470+
}
3471+
for (Int_t i = nTracks - 1; i >= 1; i--) {
3472+
Int_t j = gRandom->Integer(i + 1);
3473+
Int_t temp = tc.fRandomIndices->GetAt(j);
3474+
tc.fRandomIndices->AddAt(tc.fRandomIndices->GetAt(i), j);
3475+
tc.fRandomIndices->AddAt(temp, i);
3476+
} // end of for(Int_t i=nTracks-1;i>=1;i--)
3477+
3478+
} // void RandomIndices(Int_t nTracks)
3479+
3480+
//============================================================
3481+
34293482
void CalculateEverything()
34303483
{
34313484
// Calculate everything for selected events and particles.
@@ -3531,7 +3584,28 @@ void MainLoopOverParticles(T const& tracks)
35313584
Double_t wToPowerP = 1.; // weight raised to power p
35323585
fSelectedTracks = 0; // reset number of selected tracks
35333586

3534-
for (auto& track : tracks) {
3587+
// *) If random access of tracks from collection is requested, use Fisher-Yates algorithm to generate random indices:
3588+
if (tc.fUseFisherYates) {
3589+
if (tc.fRandomIndices) {
3590+
LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__);
3591+
}
3592+
this->RandomIndices(tracks.size());
3593+
if (!tc.fRandomIndices) {
3594+
LOGF(fatal, "in function \033[1;31m%s at line %d\033[0m", __PRETTY_FUNCTION__, __LINE__);
3595+
}
3596+
}
3597+
3598+
// *) Main loop over particles:
3599+
// for (auto& track : tracks) { // default standard way of looping of tracks
3600+
auto track = tracks.iteratorAt(0); // set the type and scope from one instance
3601+
for (int64_t i = 0; i < tracks.size(); i++) {
3602+
3603+
// *) Access track sequentially from collection of tracks (default), or randomly using Fisher-Yates algorithm:
3604+
if (!tc.fUseFisherYates) {
3605+
track = tracks.iteratorAt(i);
3606+
} else {
3607+
track = tracks.iteratorAt((int64_t)tc.fRandomIndices->GetAt(i));
3608+
}
35353609

35363610
// *) Fill particle histograms before particle cuts:
35373611
FillParticleHistograms<rs>(track, eBefore);

0 commit comments

Comments
 (0)