2525#include < Rtypes.h>
2626
2727#include < vector>
28+ #include < map>
29+ #include < array>
30+ #include < iostream>
2831
2932class MixingHandler : public TNamed
3033{
3134
3235 public:
36+
37+ // Struct to define track properties relevant for mixing and few utility functions
38+ struct MixingTrack {
39+ float pt;
40+ float eta;
41+ float phi;
42+ uint32_t filteringFlags;
43+ // flip a bit to zero (needed when a track was already used in mixing for that bit for the required pool depth)
44+ void FlipBit (int64_t mask) { filteringFlags ^= mask;}
45+ void Print () const {
46+ std::cout << " pt: " << pt << " , eta: " << eta << " , phi: " << phi << " , filteringFlags: " << filteringFlags << std::endl;
47+ }
48+ };
49+
50+ // Struct to define events used in mixing and few utility functions.
51+ // An event is defined as two vectors of tracks (typically the legs of a two-body
52+ // decay or the two-particles in a correlation analysis)
53+ struct MixingEvent {
54+ std::vector<MixingTrack> tracks1;
55+ std::vector<MixingTrack> tracks2;
56+ // bit map for active filtering bits of all the tracks
57+ uint32_t filteringMask = 0 ;
58+ // counters to keep track of how many times the event was used for mixing (for each track cut separately)
59+ std::array<short , 64 > counters = {0 };
60+ // add a track to the event and update the filtering mask accordingly
61+ void AddTrack1 (const MixingTrack& track) {
62+ tracks1.push_back (track);
63+ filteringMask |= track.filteringFlags ;
64+ }
65+ void AddTrack2 (const MixingTrack& track) {
66+ tracks2.push_back (track);
67+ filteringMask |= track.filteringFlags ;
68+ }
69+ // flip bits in the filtering mask
70+ void FlipFilteringMask (int64_t mask) { filteringMask ^= mask; }
71+ // 1) increment the counters for a given track cut bit mask and if the counters reached the pool depth,
72+ // 2) flip the corresponding bit in the tracks filtering flags to exclude them from further mixing
73+ // 3) for each track, if there are no more active bits in the filtering mask, then remove the track from the event
74+ void IncrementCounters (uint32_t mask, short poolDepth) {
75+ for (int i = 0 ; i < 32 ; i++) {
76+ if (mask & (1ULL << i)) {
77+ counters[i]++;
78+ if (counters[i] >= poolDepth) {
79+ for (auto & track : tracks1) {
80+ track.FlipBit (1ULL << i);
81+ if (track.filteringFlags == 0 ) {
82+ track = tracks1.back ();
83+ tracks1.pop_back ();
84+ }
85+ }
86+ for (auto & track : tracks2) {
87+ track.FlipBit (1ULL << i);
88+ if (track.filteringFlags == 0 ) {
89+ track = tracks2.back ();
90+ tracks2.pop_back ();
91+ }
92+ }
93+ FlipFilteringMask (1ULL << i);
94+ }
95+ }
96+ }
97+ }
98+ void Print () const {
99+ std::cout << " Event filtering mask: " ;
100+ for (int i = 0 ; i < 32 ; i++) {
101+ if (filteringMask & (1ULL << i)) {
102+ std::cout << " 1" ;
103+ } else {
104+ std::cout << " 0" ;
105+ }
106+ }
107+ std::cout << std::endl;
108+ for (int i = 0 ; i < 32 ; i++) {
109+ if (filteringMask & (1ULL << i)) {
110+ std::cout << " Counter " << i << " : " << counters[i] << std::endl;
111+ }
112+ }
113+ std::cout << " Tracks 1: " << std::endl;
114+ for (const auto & track : tracks1) {
115+ track.Print ();
116+ }
117+ std::cout << " Tracks 2: " << std::endl;
118+ for (const auto & track : tracks2) {
119+ track.Print ();
120+ }
121+ }
122+ };
123+
124+ struct MixingPool {
125+ std::vector<MixingEvent> events;
126+
127+ // check which events in the pool are empty (i.e. no active tracks for mixing) and remove them from the pool
128+ void CleanPool () {
129+ events.erase (std::remove_if (events.begin (), events.end (),
130+ [](const MixingEvent& event) { return event.tracks1 .empty () && event.tracks2 .empty (); }),
131+ events.end ());
132+ }
133+ // 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
134+ // (e.g. incrementing the counters and removing the tracks that reached the pool depth for a given cut)
135+ void UpdatePool (const MixingEvent& event, short poolDepth) {
136+ for (auto & event : events) {
137+ event.IncrementCounters (event.filteringMask , poolDepth);
138+ }
139+ CleanPool ();
140+ events.push_back (event);
141+ }
142+ // getter for the events in the pool
143+ const std::vector<MixingEvent>& GetEvents () const { return events; }
144+
145+ void Print () const {
146+ std::cout << " Mixing pool with " << events.size () << " events:" << std::endl;
147+ for (const auto & event : events) {
148+ event.Print ();
149+ }
150+ }
151+ };
152+
33153 MixingHandler ();
34154 MixingHandler (const char * name, const char * title);
35155 virtual ~MixingHandler ();
36156
37157 // setters
38- void AddMixingVariable (int var, int nBins, float * binLims);
39- void AddMixingVariable ( int var, int nBins, std::vector< float > binLims);
158+ void AddMixingVariable (int var, std::vector< float > binLims);
159+ void SetPoolDepth ( short depth) { fPoolDepth = depth; }
40160
41161 // getters
42- int GetNMixingVariables () const { return fVariables .size (); }
43- int GetMixingVariable (VarManager::Variables var); // returns the position in the internal varible list of the handler. Useful for checks, mostly
44- std::vector<float > GetMixingVariableLimits (VarManager::Variables var);
162+ // int GetNMixingVariables() const { return fVariables.size(); }
163+ // int GetMixingVariable(VarManager::Variables var); // returns the position in the internal varible list of the handler. Useful for checks, mostly
164+ // std::vector<float> GetMixingVariableLimits(VarManager::Variables var);
165+ MixingPool& GetPool (int category) { return fPools [category]; }
166+ short GetPoolDepth () const { return fPoolDepth ; }
45167
46168 void Init ();
47169 int FindEventCategory (float * values);
@@ -54,10 +176,14 @@ class MixingHandler : public TNamed
54176 // User options
55177 bool fIsInitialized ; // check if the mixing handler is initialized
56178
57- std::vector<TArrayF> fVariableLimits ;
58- std::vector<int > fVariables ;
179+ // 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
180+ std::vector<std::vector<float >> fVariableLimits ;
181+ 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)
182+
183+ short fPoolDepth ; // number of events to be kept in each pool
184+ std::map<int , MixingPool> fPools ; // key: category, value: pool of events corresponding to that category
59185
60- ClassDef (MixingHandler, 1 );
186+ ClassDef (MixingHandler, 2 );
61187};
62188
63189#endif // PWGDQ_CORE_MIXINGHANDLER_H_
0 commit comments