KaliVeda
Toolkit for HIC analysis
KVEventMixerN.h
1 #pragma once
2 
3 #include <array>
4 #include <vector>
5 #include <deque>
6 #include "KVRefVec.h"
7 
199 template<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 
235 public:
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) {
312  TreatNCor(current_bin_number, part, uncorrelated_particles);
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;
380  can_decorrelate[j] &= buffer_ready[i];
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
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)