forked from AliceO2Group/O2Physics
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMixingHandler.h
More file actions
196 lines (175 loc) · 7.02 KB
/
Copy pathMixingHandler.h
File metadata and controls
196 lines (175 loc) · 7.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
//
// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no
//
// Class to define and fill histograms
//
#ifndef PWGDQ_CORE_MIXINGHANDLER_H_
#define PWGDQ_CORE_MIXINGHANDLER_H_
#include "PWGDQ/Core/VarManager.h"
#include <TArrayF.h>
#include <TNamed.h>
#include <Rtypes.h>
#include <array>
#include <iostream>
#include <map>
#include <vector>
class MixingHandler : public TNamed
{
public:
// Struct to define track properties relevant for mixing and few utility functions
struct MixingTrack {
float pt;
float eta;
float phi;
uint32_t filteringFlags;
// flip a bit to zero (needed when a track was already used in mixing for that bit for the required pool depth)
void FlipBit(int64_t mask) { filteringFlags ^= mask; }
void Print() const
{
std::cout << "pt: " << pt << ", eta: " << eta << ", phi: " << phi << ", filteringFlags: " << filteringFlags << std::endl;
}
};
// Struct to define events used in mixing and few utility functions.
// An event is defined as two vectors of tracks (typically the legs of a two-body
// decay or the two-particles in a correlation analysis)
struct MixingEvent {
std::vector<MixingTrack> tracks1;
std::vector<MixingTrack> tracks2;
// bit map for active filtering bits of all the tracks
uint32_t filteringMask = 0;
// counters to keep track of how many times the event was used for mixing (for each track cut separately)
std::array<short, 64> counters = {0};
// add a track to the event and update the filtering mask accordingly
void AddTrack1(const MixingTrack& track)
{
tracks1.push_back(track);
filteringMask |= track.filteringFlags;
}
void AddTrack2(const MixingTrack& track)
{
tracks2.push_back(track);
filteringMask |= track.filteringFlags;
}
// flip bits in the filtering mask
void FlipFilteringMask(int64_t mask) { filteringMask ^= mask; }
// 1) increment the counters for a given track cut bit mask and if the counters reached the pool depth,
// 2) flip the corresponding bit in the tracks filtering flags to exclude them from further mixing
// 3) for each track, if there are no more active bits in the filtering mask, then remove the track from the event
void IncrementCounters(uint32_t mask, short poolDepth)
{
for (int i = 0; i < 32; i++) {
if (mask & (1ULL << i)) {
counters[i]++;
if (counters[i] >= poolDepth) {
for (auto& track : tracks1) {
track.FlipBit(1ULL << i);
if (track.filteringFlags == 0) {
track = tracks1.back();
tracks1.pop_back();
}
}
for (auto& track : tracks2) {
track.FlipBit(1ULL << i);
if (track.filteringFlags == 0) {
track = tracks2.back();
tracks2.pop_back();
}
}
FlipFilteringMask(1ULL << i);
}
}
}
}
void Print() const
{
std::cout << "Event filtering mask: ";
for (int i = 0; i < 32; i++) {
if (filteringMask & (1ULL << i)) {
std::cout << "1";
} else {
std::cout << "0";
}
}
std::cout << std::endl;
for (int i = 0; i < 32; i++) {
if (filteringMask & (1ULL << i)) {
std::cout << "Counter " << i << ": " << counters[i] << std::endl;
}
}
std::cout << "Tracks 1: " << std::endl;
for (const auto& track : tracks1) {
track.Print();
}
std::cout << "Tracks 2: " << std::endl;
for (const auto& track : tracks2) {
track.Print();
}
}
};
struct MixingPool {
std::vector<MixingEvent> events;
// check which events in the pool are empty (i.e. no active tracks for mixing) and remove them from the pool
void CleanPool()
{
events.erase(std::remove_if(events.begin(), events.end(),
[](const MixingEvent& event) { return event.tracks1.empty() && event.tracks2.empty(); }),
events.end());
}
// The function that performs the mixing is called outside this class, but the pool provides the events and tracks to be mixed and takes care of updating the events after mixing
// (e.g. incrementing the counters and removing the tracks that reached the pool depth for a given cut)
void UpdatePool(const MixingEvent& event, short poolDepth)
{
for (auto& event : events) {
event.IncrementCounters(event.filteringMask, poolDepth);
}
CleanPool();
events.push_back(event);
}
// getter for the events in the pool
const std::vector<MixingEvent>& GetEvents() const { return events; }
void Print() const
{
std::cout << "Mixing pool with " << events.size() << " events:" << std::endl;
for (const auto& event : events) {
event.Print();
}
}
};
MixingHandler();
MixingHandler(const char* name, const char* title);
virtual ~MixingHandler();
// setters
void AddMixingVariable(int var, std::vector<float> binLims);
void SetPoolDepth(short depth) { fPoolDepth = depth; }
// getters
// int GetNMixingVariables() const { return fVariables.size(); }
// int GetMixingVariable(VarManager::Variables var); // returns the position in the internal varible list of the handler. Useful for checks, mostly
// std::vector<float> GetMixingVariableLimits(VarManager::Variables var);
MixingPool& GetPool(int category) { return fPools[category]; }
short GetPoolDepth() const { return fPoolDepth; }
void Init();
int FindEventCategory(float* values);
int GetBinFromCategory(VarManager::Variables var, int category) const;
private:
MixingHandler(const MixingHandler& handler);
MixingHandler& operator=(const MixingHandler& handler);
// User options
bool fIsInitialized; // check if the mixing handler is initialized
// bin limits for the variables used for mixing, the number of vectors corresponds to the number of variables and the content of each vector corresponds to the bin limits for that variable
std::vector<std::vector<float>> fVariableLimits;
std::map<int, int> fVariables; // key: variable, value: position in the internal variable list of the handler (used to map the variables to the values passed to FindEventCategory)
short fPoolDepth; // number of events to be kept in each pool
std::map<int, MixingPool> fPools; // key: category, value: pool of events corresponding to that category
ClassDef(MixingHandler, 2);
};
#endif // PWGDQ_CORE_MIXINGHANDLER_H_