KaliVeda
Toolkit for HIC analysis
Loading...
Searching...
No Matches
KVEventMixerN.h
1#pragma once
2
3#include <array>
4#include <vector>
5#include <deque>
6#include "KVRefVec.h"
7
199template<int NPart, typename ParticleClass, typename ParticleInfoStruct, int NumBins = 1>
201
202 struct event {
203 std::vector<ParticleInfoStruct> particles;
204
205 event() = default;
206 event(event&&) = default;
207 event(const event&) = default;
208 event(const ParticleInfoStruct& p)
209 {
210 add(p);
211 }
212 void add(const ParticleInfoStruct& p)
213 {
214 particles.push_back(p);
215 }
216 };
217
218 using event_buffer = std::deque<event>;
219 struct bin_data {
220 std::vector<event_buffer> part_events = std::vector<event_buffer>(NPart);
221 };
222 bin_data bins[NumBins];
223
224 typename event_buffer::size_type decor_events = 10;
225
227 std::array<int, NPart> n_part;
228 std::array<bool, NPart> mult_fixed;
229 std::array<bool, NPart> buffer_ready;
230 std::array<bool, NPart> can_decorrelate;
231
234
235public:
241 KVEventMixerN(typename event_buffer::size_type number_of_events_to_mix = 10)
242 : decor_events{number_of_events_to_mix}
243 {}
244
245 template<typename TreatCorFunc>
246 void process_event(int, TreatCorFunc TreatCor)
247 {
248 // After recursive calls to process_event() have emptied the parameter pack part_iterator_list
249 // (in other words, iterations over all particle types have been treated and the vector correlated_particles
250 // has been filled with one particle of each type from the current event), this method is
251 // called in order to dispatch the call to the user's function for correlated multiplets, TreatCor()
253 }
254
255 template<typename TreatCorFunc, typename part_iterator, typename... part_iterator_list>
256 void process_event(int part_index, TreatCorFunc TreatCor, part_iterator& iter_part, part_iterator_list... part_iterators)
257 {
258 // This method is called recursively in order to iterate over each type of particle in the current event,
259 // calculate the multiplicities (stored in n_part[] vector), and store in the buffers for the
260 // current bin/event class. The correlated_particles vector is filled with NPart references to
261 // a particle of each type, in order to call the user's TreatCor() function.
262 ++part_index;
263 bool count_and_store = true;
264 // for part_index>0 we only increment the multipicity and store the particle in buffers the first
265 // time that we visit, i.e. only if n_part[0]==1 && n_part[1]==1 && ... && n_part[part_index-1]==1
266 if (part_index > 0) {
267 for (int i = 0; i < part_index; ++i) count_and_store &= (n_part[i] == 1);
268 }
269 for (auto& part : iter_part) {
270 if (count_and_store) {
271 ++n_part[part_index]; // count multiplicity of particles
272 if (n_part[part_index] == 1) bins[current_bin_number].part_events[part_index].push_back(ParticleInfoStruct(part));
273 else bins[current_bin_number].part_events[part_index].back().add(ParticleInfoStruct(part));
274 }
275 // store reference to particle for call to TreatCor
276 correlated_particles.set(part_index, &part);
277 process_event(part_index, TreatCor, part_iterators...);
278 }
279 }
280
282 {
283 // Dummy method, called at end of recursive calls to fill_all_particle_buffers() when all
284 // iterators in the parameter pack part_iterators have been treated.
285 }
286
287 template<typename part_iterator, typename... part_iterator_list>
288 void fill_all_particle_buffers(int part_index, part_iterator& iter_part, part_iterator_list... part_iterators)
289 {
290 // This method is called recursively to ensure that all particles from the current event are stored in
291 // the decorrelating buffers, even if the event does not contain at least one particle of each of the NPart types
292 // (depending on the user's event selection).
293 ++part_index;
294 if (part_index == 0) fill_all_particle_buffers(part_index, part_iterators...);
295 else {
296 if (!n_part[part_index] && (!n_part[part_index - 1] || mult_fixed[part_index - 1])) {
297 mult_fixed[part_index] = true;
298 for (auto& part : iter_part) {
299 ++n_part[part_index]; // count multiplicity of particles
300 if (n_part[part_index] == 1) bins[current_bin_number].part_events[part_index].push_back(ParticleInfoStruct(part));
301 else bins[current_bin_number].part_events[part_index].back().add(ParticleInfoStruct(part));
302 }
303 }
304 fill_all_particle_buffers(part_index, part_iterators...);
305 }
306 }
307
308 template<typename TreatNCorFunc>
309 void recursive_decorrelation(ParticleClass& part, int part_index, int decor_index, int decor_vec_index, TreatNCorFunc TreatNCor)
310 {
311 if (decor_index == NPart) {
313 }
314 else if (decor_index != part_index) {
315 // loop over events & particles in buffer
316 auto& event_buffer = bins[current_bin_number].part_events[decor_index];
317 for (size_t i = 0; i < decor_events; ++i) {
318 for (auto& _part : event_buffer[i].particles) {
319 // add to uncorrelated particle vector
320 uncorrelated_particles.set(decor_vec_index, &_part);
321 recursive_decorrelation(part, part_index, (decor_index + 1), (decor_vec_index + 1), TreatNCor);
322 }
323 }
324 }
325 else // can't decorrelate particle with particles of same type
326 recursive_decorrelation(part, part_index, (decor_index + 1), decor_vec_index, TreatNCor);
327 }
328
329 template<typename TreatNCorFunc>
330 void decorrelate(int, TreatNCorFunc)
331 {}
332
333 template<typename TreatNCorFunc, typename part_iterator, typename... part_iterator_list>
334 void decorrelate(int part_index, TreatNCorFunc TreatNCor, part_iterator& iter_part, part_iterator_list... part_iterators)
335 {
336 // DECORRELATION
337 // Each particle of type part_index in the current event is coupled with all the particles in the buffers
338 // of the other types of particles as long as they are all sufficiently full i.e. with decor_events in them
339 ++part_index;
340 if (n_part[part_index] && can_decorrelate[part_index]) {
341 for (auto& part : iter_part) {
342 recursive_decorrelation(part, part_index, 0, 0, TreatNCor);
343 }
344 }
345 decorrelate(part_index, TreatNCor, part_iterators...);
346 }
347
348 template<typename TreatCorFunc, typename TreatNCorFunc, typename part_iterator, typename... part_iterator_list>
349 void ProcessEvent(int bin_number, TreatCorFunc TreatCor, TreatNCorFunc TreatNCor, const part_iterator& iter_part, part_iterator_list... part_iterators)
350 {
351 current_bin_number = bin_number;
352 // set all particle multiplicities to zero
353 for (int i = 0; i < NPart; ++i) {
354 n_part[i] = 0;
355 mult_fixed[i] = false;
356 can_decorrelate[i] = true;
357 }
358
359 // recursively iterate over all N-tuples of particles, updating multiplicities, filling buffers,
360 // and calling the TreatCor function
361 process_event(-1, TreatCor, iter_part, part_iterators...);
362
363 // make sure all particles from event are added to mixing buffers
364 // in process_event(), if there are no A particles, B,C,D,... are not even looked at
365 // if there are A particles but not B, C,D,... are not even looked at
366 // if there are A & B particles but not C, D,... are not even looked at etc.
367 fill_all_particle_buffers(-1, iter_part, part_iterators...);
368
369 // now check each buffer is ready for decorrelation -
370 // either:
371 // the buffer contains decor_events (the current event was not added)
372 // or
373 // the buffer contains decor_events+1 (the current event was added)
374 for (int i = 0; i < NPart; ++i) {
375 auto buf_siz = bins[current_bin_number].part_events[i].size();
376 buffer_ready[i] = ((buf_siz == decor_events) && !n_part[i]) || ((buf_siz == decor_events + 1) && n_part[i]);
377 // this buffer can be used to decorrelate all particle types except itself
378 for (int j = 0; j < NPart; ++j) {
379 if (j == i) continue;
381 }
382 }
383
384 // DECORRELATION
385 decorrelate(-1, TreatNCor, iter_part, part_iterators...);
386
387 // now we remove (if necessary) the oldest event in each buffer, to keep only decor_events
388 for (int i = 0; i < NPart; ++i) {
389 if (bins[current_bin_number].part_events[i].size() > decor_events) {
390 // remove oldest (first) event
391 bins[current_bin_number].part_events[i].pop_front();
392 }
393 }
394 }
395};
size_t size(const MatrixT &matrix)
winID h TVirtualViewer3D TVirtualGLPainter p
Generic event mixing algorithm for N-particle correlation studies.
KVEventMixerN(typename event_buffer::size_type number_of_events_to_mix=10)
vector of references to particles from buffers for decorrelation
bin_data bins[NumBins]
void fill_all_particle_buffers(int part_index, part_iterator &iter_part, part_iterator_list... part_iterators)
std::array< int, NPart > n_part
bin number passed in current call to ProcessEvent
void decorrelate(int part_index, TreatNCorFunc TreatNCor, part_iterator &iter_part, part_iterator_list... part_iterators)
std::array< bool, NPart > buffer_ready
void process_event(int, TreatCorFunc TreatCor)
void decorrelate(int, TreatNCorFunc)
std::array< bool, NPart > mult_fixed
particle multiplicities for event being treated by ProcessEvent
void process_event(int part_index, TreatCorFunc TreatCor, part_iterator &iter_part, part_iterator_list... part_iterators)
void ProcessEvent(int bin_number, TreatCorFunc TreatCor, TreatNCorFunc TreatNCor, const part_iterator &iter_part, part_iterator_list... part_iterators)
std::array< bool, NPart > can_decorrelate
void fill_all_particle_buffers(int)
int current_bin_number
number of events used for decorrelation (event mixing)
event_buffer::size_type decor_events
KVRefVec< ParticleClass > correlated_particles
std::deque< event > event_buffer
void recursive_decorrelation(ParticleClass &part, int part_index, int decor_index, int decor_vec_index, TreatNCorFunc TreatNCor)
KVRefVec< ParticleInfoStruct > uncorrelated_particles
vector of references to particles in current event
Vector of references to objects.
Definition KVRefVec.h:24
void set(size_t i, T *t)
Definition KVRefVec.h:32
std::vector< event_buffer > part_events
event(event &&)=default
std::vector< ParticleInfoStruct > particles
event(const ParticleInfoStruct &p)
event(const event &)=default
void add(const ParticleInfoStruct &p)