rivet is hosted by Hepforge, IPPP Durham
Rivet  2.7.0
Correlators.hh
1 // -*- C++ -*-
2 #ifndef RIVET_Correlators_HH
3 #define RIVET_Correlators_HH
4 
5 #include "Rivet/Projection.hh"
6 #include "Rivet/Projections/ParticleFinder.hh"
7 #include <complex>
8 #include "YODA/Scatter2D.h"
9 #include "Rivet/Analysis.hh"
10 /* File contains tools for calculating flow coefficients using
11  * correlators.
12  * Classes:
13  * Correlators: Calculates single event correlators of a given harmonic.
14  * Cumulants: An additional base class for flow analyses
15  * (use as: class MyAnalysis : public Analysis, Cumulants {};)
16  * Includes a framework for calculating cumulants and flow coefficients
17  * from single event correlators, including automatic handling of statistical
18  * errors. Contains multiple internal sub-classes:
19  * CorBinBase: Base class for correlators binned in event or particle observables.
20  * CorSingleBin: A simple bin for correlators.
21  * CorBin: Has the interface of a simple bin, but does automatic calculation
22  * of statistical errors by a bootstrap method.
23  * ECorrelator: Data type for event averaged correlators.
24  * @author Vytautas Vislavicius, Christine O. Rasmussen, Christian Bierlich.
25  */
26 
27 namespace Rivet {
28 
29  /* @brief Projection for calculating correlators for flow measurements.
30  *
31  * A projection which calculates Q-vectors and P-vectors, and projects
32  * them out as correlators. Implementation follows the description of
33  * the ''Generic Framework''
34  * Phys. Rev. C 83 (2011) 044913, arXiv: 1010.0233
35  * Phys. Rev. C 89 (2014) 064904, arXiv: 1312.3572
36  *
37  */
38 
39  class Correlators : public Projection {
40 
41  public:
42 
43  // Constructor. Takes parameters @parm fsp, the Final State
44  // projection correlators should be constructed from, @parm nMaxIn,
45  // the maximal sum of harmonics, eg. for
46  // c_2{2} = {2,-2} = 2 + 2 = 4
47  // c_2{4} = {2,2,-2,-2} = 2 + 2 + 2 + 2 = 8
48  // c_4{2} = {4,-4} = 4 + 4 = 8
49  // c_4{4} = {4,4,-4,-4} = 4 + 4 + 4 + 4 = 16.
50  // @parm pMaxIn is the maximal number of particles
51  // you want to correlate and @parm pTbinEdgesIn is the (lower)
52  // edges of pT bins, the last one the upper edge of the final bin.
53  Correlators(const ParticleFinder& fsp, int nMaxIn = 2,
54  int pMaxIn = 0, vector<double> pTbinEdgesIn = {});
55 
56  // Constructor which takes a Scatter2D to estimate bin edges.
57  Correlators(const ParticleFinder& fsp, int nMaxIn,
58  int pMaxIn, const Scatter2DPtr hIn);
59 
67  const pair<double,double> intCorrelator(vector<int> n) const;
68 
74  const vector<pair<double,double>> pTBinnedCorrelators(vector<int> n,
75  bool overflow = false) const;
76 
85  const pair<double,double> intCorrelatorGap(const Correlators& other,
86  vector<int> n1, vector<int> n2) const;
87 
101  const vector<pair<double,double>> pTBinnedCorrelatorsGap(
102  const Correlators& other, vector<int> n1, vector<int> n2,
103  bool oveflow = false) const;
104 
108  static vector<int> hVec(int n, int m) {
109  if (m%2 != 0) {
110  cout << "Harmonic Vector: Number of particles "
111  "must be an even number." << endl;
112  return {};
113  }
114  vector<int> ret = {};
115  for (int i = 0; i < m; ++i) {
116  if (i < m/2) ret.push_back(n);
117  else ret.push_back(-n);
118  }
119  return ret;
120  }
121 
124  static pair<int,int> getMaxValues(vector< vector<int> >& hList){
125  int nMax = 0, pMax = 0;
126  for (vector<int> h : hList) {
127  int tmpN = 0, tmpP = 0;
128  for ( int i = 0; i < int(h.size()); ++i) {
129  tmpN += abs(h[i]);
130  ++tmpP;
131  }
132  if (tmpN > nMax) nMax = tmpN;
133  if (tmpP > pMax) pMax = tmpP;
134  }
135  return make_pair(nMax,pMax);
136  }
137  // Clone on the heap.
138  DEFAULT_RIVET_PROJ_CLONE(Correlators);
139 
140  protected:
141 
142  // @brief Project function. Loops over array and calculates Q vectors
143  // and P vectors if needed
144  void project(const Event& e);
145 
146  // @brief Compare against other projection. Test if harmonics, pT-bins
147  // and underlying final state are similar.
148  int compare(const Projection& p) const {
149  const Correlators* other = dynamic_cast<const Correlators*>(&p);
150  if (nMax != other->nMax) return UNDEFINED;
151  if (pMax != other->pMax) return UNDEFINED;
152  if (pTbinEdges != other->pTbinEdges) return UNDEFINED;
153  return mkPCmp(p, "FS");
154  };
155 
156  // @brief Calculate correlators from one particle.
157  void fillCorrelators(const Particle& p, const double& weight);
158 
159  // @brief Return a Q-vector.
160  const complex<double> getQ(int n, int p) const {
161  bool isNeg = (n < 0);
162  if (isNeg) return conj( qVec[abs(n)][p] );
163  else return qVec[n][p];
164  };
165 
166  // @brief Return a P-vector.
167  const complex<double> getP(int n, int p, double pT = 0.) const {
168  bool isNeg = (n < 0);
169  map<double, Vec2D>::const_iterator pTitr = pVec.lower_bound(pT);
170  if (pTitr == pVec.end()) return DBL_NAN;
171  if (isNeg) return conj( pTitr->second[abs(n)][p] );
172  else return pTitr->second[n][p];
173  };
174 
175  private:
176  // Find correlators by recursion. Order = M (# of particles),
177  // n's are harmonics, p's are the powers of the weights
178  const complex<double> recCorr(int order, vector<int> n,
179  vector<int> p, bool useP, double pT = 0.) const;
180 
181  // Two-particle correlator Eq. (19) p. 6
182  // Flag if p-vectors or q-vectors should be used to
183  // calculate the correlator.
184  const complex<double> twoPartCorr(int n1, int n2, int p1 = 1,
185  int p2 = 1, double pT = 0., bool useP = false) const;
186 
187  // Set elements in vectors to zero.
188  void setToZero();
189 
190  // Shorthands for setting and comparing to zero.
191  const complex<double> _ZERO = {0., 0.};
192  const double _TINY = 1e-10;
193 
194  // Shorthand typedefs for vec<vec<complex>>.
195  typedef vector< vector<complex<double>> > Vec2D;
196 
197  // Define Q-vectors and p-vectors
198  Vec2D qVec; // Q[n][p]
199  map<double, Vec2D> pVec; // p[pT][n][p]
200 
201  // The max values of n and p to be calculated.
202  int nMax, pMax;
203  // pT bin-edges
204  vector<double> pTbinEdges;
205  bool isPtDiff;
206 
208  };
209 
210 
214  // correlators defined above. They are all encapsulated in a Cumulants
215  // class, which can be used as a(nother) base class for flow analyses,
216  // to ensure access.
217 
218  class CumulantAnalysis : public Analysis {
219  private:
220 
221  // Number of bins used for bootstrap calculation of statistical
222  // uncertainties. It is hard coded, and shout NOT be changed unless there
223  // are good reasons to do so.
224  static const int BOOT_BINS = 9;
225 
226  // Enum for choosing the method of error calculation.
227  enum Error {
228  VARIANCE,
229  ENVELOPE
230  };
231 
232  // The desired error method. Can be changed in the analysis constructor
233  // by setting it appropriately.
234  Error errorMethod;
235 
237  class CorBinBase {
238  public:
239  CorBinBase() {}
240  virtual ~CorBinBase() {};
241  // Derived class should have fill and mean defined.
242  virtual void fill(const pair<double, double>& cor, const double& weight) = 0;
243  virtual const double mean() const = 0;
244  };
245 
250  class CorSingleBin : public CorBinBase {
251 
252  public:
254  CorSingleBin() : _sumWX(0.), _sumW(0.), _sumW2(0.), _numEntries(0.) {}
255 
256  ~CorSingleBin() {}
259  void fill(const pair<double, double>& cor, const double& weight) {
260  // Test if denominator for the single event average is zero.
261  if (cor.second < 1e-10) return;
262  // The single event average <M> is then cor.first / cor.second.
263  // With weights this becomes just:
264  _sumWX += cor.first * weight;
265  _sumW += weight * cor.second;
266  _sumW2 += weight * weight * cor.second * cor.second;
267  _numEntries += 1.;
268  }
269 
270  const double mean() const {
271  if (_sumW < 1e-10) return 0;
272  return _sumWX / _sumW;
273  }
274 
275  // @brief Sum of weights.
276  const double sumW() const {
277  return _sumW;
278  }
279 
280  const double sumW2() const {
281  return _sumW2;
282  }
283 
284  // @brief Sum of weight * X.
285  const double sumWX() const {
286  return _sumWX;
287  }
288 
289  // @brief Number of entries.
290  const double numEntries() const {
291  return _numEntries;
292  }
293 
294  void addContent(double ne, double sw, double sw2, double swx) {
295  _numEntries += ne;
296  _sumW += sw;
297  _sumW2 += sw2;
298  _sumWX += swx;
299  }
300 
301  private:
302  double _sumWX, _sumW, _sumW2, _numEntries;
303 
304  }; // End of CorSingleBin sub-class.
305 
309  class CorBin : public CorBinBase {
310  public:
311  // @brief The constructor. nBins signifies the period of the bootstrap
312  // calculation, and should never be changed here, but in its definition
313  // above -- and only if there are good reasons to do so.
314  CorBin() : binIndex(0), nBins(BOOT_BINS) {
315  for(size_t i = 0; i < nBins; ++i) bins.push_back(CorSingleBin());
316  }
317  // Destructor must be implemented.
318 
319  ~CorBin() {}
320  // @brief Fill the correct underlying bin and take a step.
321  void fill(const pair<double, double>& cor, const double& weight) {
322  // Test if denominator for the single event average is zero.
323  if (cor.second < 1e-10) return;
324  // Fill the correct bin.
325  bins[binIndex].fill(cor, weight);
326  if (binIndex == nBins - 1) binIndex = 0;
327  else ++binIndex;
328  }
329 
330  // @brief Calculate the total sample mean with all
331  // available statistics.
332  const double mean() const {
333  double sow = 0;
334  double sowx = 0;
335  for(auto b : bins) {
336  if (b.sumW() < 1e-10) continue;
337  sow += b.sumW();
338  sowx += b.sumWX();
339  }
340  return sowx / sow;
341  }
342 
343  // @brief Return a copy of the bins.
344  const vector<CorSingleBin> getBins() const {
345  return bins;
346  }
347 
348  // @brief Return the bins as pointers to the base class.
349  template<class T=CorBinBase>
350  const vector<T*> getBinPtrs() {
351  vector<T*> ret(bins.size());
352  transform(bins.begin(), bins.end(), ret.begin(),
353  [](CorSingleBin& b) {return &b;});
354  return ret;
355  }
356 
357  private:
358  vector<CorSingleBin> bins;
359  size_t binIndex;
360  size_t nBins;
361 
362  }; // End of CorBin sub-class.
363 
364  public:
368  class ECorrelator {
369 
370  public:
375  //ECorrelator(vector<int> h) : h1(h), h2({}),
376  // binX(0), binContent(0), reference() {
377  //};
378 
382  ECorrelator(vector<int> h, vector<double> binIn) : h1(h), h2({}),
383  binX(binIn), binContent(binIn.size() - 1), reference() {};
384 
387  ECorrelator(vector<int> h1In, vector<int> h2In, vector<double> binIn) :
388  h1(h1In), h2(h2In), binX(binIn), binContent(binIn.size() - 1),
389  reference() {};
390 
393  void fill(const double& obs, const Correlators& c,
394  const double weight = 1.0) {
395  int index = getBinIndex(obs);
396  if (index < 0) return;
397  binContent[index].fill(c.intCorrelator(h1), weight);
398  }
399 
403  void fill(const double& obs, const Correlators& c1,
404  const Correlators& c2, const double weight = 1.0) {
405  if (!h2.size()) {
406  cout << "Trying to fill gapped correlator, but harmonics behind "
407  "the gap (h2) are not given!" << endl;
408  return;
409  }
410  int index = getBinIndex(obs);
411  if (index < 0) return;
412  binContent[index].fill(c1.intCorrelatorGap(c2, h1, h2), weight);
413  }
414 
418  void fill(const Correlators& c, const double& weight = 1.0) {
419  vector< pair<double, double> > diffCorr = c.pTBinnedCorrelators(h1);
420  // We always skip overflow when calculating the all event average.
421  if (diffCorr.size() != binX.size() - 1)
422  cout << "Tried to fill event with wrong binning (ungapped)" << endl;
423  for (size_t i = 0; i < diffCorr.size(); ++i) {
424  int index = getBinIndex(binX[i]);
425  if (index < 0) return;
426  binContent[index].fill(diffCorr[i], weight);
427  }
428  reference.fill(c.intCorrelator(h1), weight);
429  }
430 
434  void fill(const Correlators& c1, const Correlators& c2,
435  const double& weight = 1.0) {
436  if (!h2.size()) {
437  cout << "Trying to fill gapped correlator, but harmonics behind "
438  "the gap (h2) are not given!" << endl;
439  return;
440  }
441  vector< pair<double, double> > diffCorr = c1.pTBinnedCorrelatorsGap(c2, h1, h2);
442  // We always skip overflow when calculating the all event average.
443  if (diffCorr.size() != binX.size() - 1)
444  cout << "Tried to fill event with wrong binning (gapped)" << endl;
445  for (size_t i = 0; i < diffCorr.size(); ++i) {
446  int index = getBinIndex(binX[i]);
447  if (index < 0) return;
448  binContent[index].fill(diffCorr[i], weight);
449  }
450  reference.fill(c1.intCorrelatorGap(c2, h1, h2), weight);
451  }
452 
454  const vector<CorBin> getBins() const {
455  return binContent;
456  }
457 
458  // @brief Return the bins as pointers to the base class.
459  const vector<CorBinBase*> getBinPtrs() {
460  vector<CorBinBase*> ret(binContent.size());
461  transform(binContent.begin(), binContent.end(), ret.begin(),
462  [](CorBin& b) {return &b;});
463  return ret;
464  }
465 
467  const vector<double> getBinX() const {
468  return binX;
469  }
470 
472  const vector<int> getH1() const {
473  return h1;
474  }
475 
477  const vector<int> getH2() const {
478  return h2;
479  }
480 
484  void setReference(CorBin refIn) {
485  reference = refIn;
486  }
487 
490  const CorBin getReference() const {
491  if (reference.mean() < 1e-10)
492  cout << "Warning: ECorrelator, reference bin is zero." << endl;
493  return reference;
494  }
498  void setProfs(list<Profile1DPtr> prIn) {
499  profs = prIn;
500  }
501 
503  void fillFromProfs() {
504  list<Profile1DPtr>::iterator hItr = profs.begin();
505  auto refs = reference.getBinPtrs<CorSingleBin>();
506  for (size_t i = 0; i < profs.size(); ++i, ++hItr) {
507  for (size_t j = 0; j < binX.size() - 1; ++j) {
508  const YODA::ProfileBin1D& pBin = (*hItr)->binAt(binX[j]);
509  auto tmp = binContent[j].getBinPtrs<CorSingleBin>();
510  tmp[i]->addContent(pBin.numEntries(), pBin.sumW(), pBin.sumW2(),
511  pBin.sumWY());
512  }
513  // Get the reference flow from the underflow bin of the histogram.
514  const YODA::Dbn2D& uBin = (*hItr)->underflow();
515  refs[i]->addContent(uBin.numEntries(), uBin.sumW(), uBin.sumW2(),
516  uBin.sumWY());
517  } // End loop of bootstrapped correlators.
518 
519  }
520 
522  list<Profile1DPtr>::iterator profBegin() {
523  return profs.begin();
524  }
525 
527  list<Profile1DPtr>::iterator profEnd() {
528  return profs.end();
529  }
530 
531  private:
533  const int getBinIndex(const double& obs) const {
534  // Find the correct index of binContent.
535  // If we are in overflow, just skip.
536  if (obs >= binX.back()) return -1;
537  // If we are in underflow, ditto.
538  if (obs < binX[0]) return -1;
539  int index = 0;
540  for (int i = 0, N = binX.size() - 1; i < N; ++i, ++index)
541  if (obs >= binX[i] && obs < binX[i + 1]) break;
542  return index;
543  }
544 
545  // The harmonics vectors.
546  vector<int> h1;
547  vector<int> h2;
548  // The bins.
549  vector<double> binX;
550  vector<CorBin> binContent;
551  // The reference flow.
552  CorBin reference;
553  // The profile histograms associated with the CorBins for streaming.
554  list<Profile1DPtr> profs;
555 
556  }; // End of ECorrelator sub-class.
557 
558  // @brief Get the correct max N and max P for the set of
559  // booked correlators.
560  const pair<int, int> getMaxValues() const {
561  vector< vector<int>> harmVecs;
562  for ( auto eItr = eCorrPtrs.begin(); eItr != eCorrPtrs.end(); ++eItr) {
563  vector<int> h1 = (*eItr)->getH1();
564  vector<int> h2 = (*eItr)->getH2();
565  if (h1.size() > 0) harmVecs.push_back(h1);
566  if (h2.size() > 0) harmVecs.push_back(h2);
567  }
568  if (harmVecs.size() == 0) {
569  cout << "Warning: You tried to extract max values from harmonic "
570  "vectors, but have not booked any." << endl;
571  return pair<int,int>();
572  }
573  return Correlators::getMaxValues(harmVecs);
574  }
575 
576  // Typedeffing shared pointer to ECorrelator.
577  typedef shared_ptr<ECorrelator> ECorrPtr;
578 
579  // @brief Book an ECorrelator in the same way as a histogram.
580  ECorrPtr bookECorrelator(const string name, const vector<int>& h, const Scatter2DPtr hIn) {
581  vector<double> binIn;
582  for (auto b : hIn->points()) binIn.push_back(b.xMin());
583  binIn.push_back(hIn->points().back().xMax());
584  ECorrPtr ecPtr = ECorrPtr(new ECorrelator(h, binIn));
585  list<Profile1DPtr> eCorrProfs;
586  for (int i = 0; i < BOOT_BINS; ++i) {
587  Profile1DPtr tmp = bookProfile1D(name+"-"+to_string(i),*hIn);
588  tmp->setPath(this->name()+"/FINAL/" + name+"-"+to_string(i));
589  //tmp->setPath(tmp->path()+"FINAL");
590  eCorrProfs.push_back(tmp);
591  }
592  ecPtr->setProfs(eCorrProfs);
593  eCorrPtrs.push_back(ecPtr);
594  return ecPtr;
595  }
596 
597  // @brief Book a gapped ECorrelator with two harmonic vectors.
598  ECorrPtr bookECorrelator(const string name, const vector<int>& h1,
599  const vector<int>& h2, const Scatter2DPtr hIn ) {
600  vector<double> binIn;
601  for (auto b : hIn->points()) binIn.push_back(b.xMin());
602  binIn.push_back(hIn->points().back().xMax());
603  ECorrPtr ecPtr = ECorrPtr(new ECorrelator(h1, h2, binIn));
604  list<Profile1DPtr> eCorrProfs;
605  for (int i = 0; i < BOOT_BINS; ++i) {
606  Profile1DPtr tmp = bookProfile1D(name+"-"+to_string(i),*hIn);
607  tmp->setPath(this->name()+"/FINAL/" + name+"-"+to_string(i));
608  //tmp->setPath(tmp->path()+"FINAL");
609  eCorrProfs.push_back(tmp);
610  }
611  ecPtr->setProfs(eCorrProfs);
612  eCorrPtrs.push_back(ecPtr);
613  return ecPtr;
614  }
615 
616  // @brief Short hand for gapped correlators which splits the harmonic
617  // vector into negative and positive components.
618  ECorrPtr bookECorrelatorGap (const string name, const vector<int>& h,
619  const Scatter2DPtr hIn) {
620  const vector<int> h1(h.begin(), h.begin() + h.size() / 2);
621  const vector<int> h2(h.begin() + h.size() / 2, h.end());
622  return bookECorrelator(name, h1, h2, hIn);
623  }
624 
625 
626  // @brief Templated version of correlator booking which takes
627  // @parm N desired harmonic and @parm M number of particles.
628  template<unsigned int N, unsigned int M>
629  ECorrPtr bookECorrelator(const string name, const Scatter2DPtr hIn) {
630  return bookECorrelator(name, Correlators::hVec(N, M), hIn);
631  }
632 
633  // @brief Templated version of gapped correlator booking which takes
634  // @parm N desired harmonic and @parm M number of particles.
635  template<unsigned int N, unsigned int M>
636  ECorrPtr bookECorrelatorGap(const string name, const Scatter2DPtr hIn) {
637  return bookECorrelatorGap(name, Correlators::hVec(N, M), hIn);
638  }
639 
640  // @brief The stream method MUST be called in finalize() if one wants to stream
641  // correlators to the yoda file, in order to do reentrant finalize
642  // (ie. multi-histogram merging) for the analysis.
643  void stream() {
644  for (auto ecItr = eCorrPtrs.begin(); ecItr != eCorrPtrs.end(); ++ecItr){
645  (*ecItr)->fillFromProfs();
646  corrPlot(list<Profile1DPtr>((*ecItr)->profBegin(),
647  (*ecItr)->profEnd()), *ecItr);
648  }
649  }
650  private:
651 
653  list<ECorrPtr> eCorrPtrs;
654 
655  public:
656 
657  // @brief Constructor. Use CumulantAnalysis as base class for the
658  // analysis to have access to functionality.
659  CumulantAnalysis (string n) : Analysis(n), errorMethod(VARIANCE) {};
660  // @brief Helper method for turning correlators into Scatter2Ds.
661  // Takes @parm h a pointer to the resulting Scatter2D, @parm binx
662  // the x-bins and a function @parm func defining the transformation.
663  // Makes no attempt at statistical errors.
664  // See usage in the methods below.
665  // Can also be used directly in the analysis if a user wants to
666  // perform an unforseen transformation from correlators to
667  // Scatter2D.
668  template<typename T>
669  static void fillScatter(Scatter2DPtr h, vector<double>& binx, T func) {
670  vector<YODA::Point2D> points;
671  for (int i = 0, N = binx.size() - 1; i < N; ++i) {
672  double xMid = (binx[i] + binx[i + 1]) / 2.0;
673  double xeMin = fabs(xMid - binx[i]);
674  double xeMax = fabs(xMid - binx[i + 1]);
675  double yVal = func(i);
676  if (std::isnan(yVal)) yVal = 0.;
677  double yErr = 0;
678  points.push_back(YODA::Point2D(xMid, yVal, xeMin, xeMax, yErr, yErr));
679  }
680  h->reset();
681  h->points().clear();
682  for (int i = 0, N = points.size(); i < N; ++i) h->addPoint(points[i]);
683  }
684 
685  // @brief Helper method for turning correlators into Scatter2Ds
686  // with error estimates.
687  // Takes @parm h a pointer to the resulting Scatter2D, @parm binx
688  // the x-bins, a function @parm func defining the transformation
689  // and a vector of errors @parm err.
690  // See usage in the methods below.
691  // Can also be used directly in the analysis if a user wants to
692  // perform an unforseen transformation from correlators to
693  // Scatter2D.
694  template<typename F>
695  const void fillScatter(Scatter2DPtr h, vector<double>& binx, F func,
696  vector<pair<double, double> >& yErr) const {
697  vector<YODA::Point2D> points;
698  for (int i = 0, N = binx.size() - 1; i < N; ++i) {
699  double xMid = (binx[i] + binx[i + 1]) / 2.0;
700  double xeMin = fabs(xMid - binx[i]);
701  double xeMax = fabs(xMid - binx[i + 1]);
702  double yVal = func(i);
703  if (std::isnan(yVal))
704  points.push_back(YODA::Point2D(xMid, 0., xeMin, xeMax,0., 0.));
705  else
706  points.push_back(YODA::Point2D(xMid, yVal, xeMin, xeMax,
707  yErr[i].first, yErr[i].second));
708  }
709  h->reset();
710  h->points().clear();
711  for (int i = 0, N = points.size(); i < N; ++i)
712  h->addPoint(points[i]);
713  }
714 
715 
719  static void nthPow(Scatter2DPtr hOut, const Scatter2DPtr hIn,
720  const double& n, const double& k = 1.0) {
721  if (n == 0 || n == 1) {
722  cout << "Error: Do not take the 0th or 1st power of a Scatter2D,"
723  " use scale instead." << endl;
724  return;
725  }
726  if (hIn->points().size() != hOut->points().size()) {
727  cout << "nthRoot: Scatterplots: " << hIn->name() << " and " <<
728  hOut->name() << " not initialized with same length." << endl;
729  return;
730  }
731  vector<YODA::Point2D> points;
732  // The error pre-factor is k^(1/n) / n by Taylors formula.
733  double eFac = pow(k,1./n)/n;
734  for (auto b : hIn->points()) {
735  double yVal = pow(k * b.y(),n);
736  if (std::isnan(yVal))
737  points.push_back(YODA::Point2D(b.x(), 0., b.xErrMinus(),
738  b.xErrPlus(), 0, 0 ));
739  else {
740  double yemin = abs(eFac * pow(yVal,1./(n - 1.))) * b.yErrMinus();
741  if (std::isnan(yemin)) yemin = b.yErrMinus();
742  double yemax = abs(eFac * pow(yVal,1./(n - 1.))) * b.yErrPlus();
743  if (std::isnan(yemax)) yemax = b.yErrPlus();
744  points.push_back(YODA::Point2D(b.x(), yVal, b.xErrMinus(),
745  b.xErrPlus(), yemin, yemax ));
746  }
747  }
748  hOut->reset();
749  hOut->points().clear();
750  for (int i = 0, N = points.size(); i < N; ++i)
751  hOut->addPoint(points[i]);
752  }
753 
757  static void nthPow(Scatter2DPtr h, const double& n,
758  const double& k = 1.0) {
759  if (n == 0 || n == 1) {
760  cout << "Error: Do not take the 0th or 1st power of a Scatter2D,"
761  " use scale instead." << endl;
762  return;
763  }
764  vector<YODA::Point2D> points;
765  vector<YODA::Point2D> pIn = h->points();
766  // The error pre-factor is k^(1/n) / n by Taylors formula.
767  double eFac = pow(k,1./n)/n;
768  for (auto b : pIn) {
769  double yVal = pow(k * b.y(),n);
770  if (std::isnan(yVal))
771  points.push_back(YODA::Point2D(b.x(), 0., b.xErrMinus(),
772  b.xErrPlus(), 0, 0 ));
773  else {
774  double yemin = abs(eFac * pow(yVal,1./(n - 1.))) * b.yErrMinus();
775  if (std::isnan(yemin)) yemin = b.yErrMinus();
776  double yemax = abs(eFac * pow(yVal,1./(n - 1.))) * b.yErrPlus();
777  if (std::isnan(yemax)) yemax = b.yErrPlus();
778  points.push_back(YODA::Point2D(b.x(), yVal, b.xErrMinus(),
779  b.xErrPlus(), yemin, yemax ));
780  }
781  }
782  h->reset();
783  h->points().clear();
784  for (int i = 0, N = points.size(); i < N; ++i) h->addPoint(points[i]);
785  }
786 
787  // @brief Calculate the bootstrapped sample variance for the observable
788  // given by correlators and the transformation @parm func.
789  template<typename T>
790  static pair<double, double> sampleVariance(T func) {
791  // First we calculate the mean (two pass calculation).
792  double avg = 0.;
793  for (int i = 0; i < BOOT_BINS; ++i) avg += func(i);
794  avg /= double(BOOT_BINS);
795  // Then we find the variance.
796  double var = 0.;
797  for (int i = 0; i < BOOT_BINS; ++i) var += pow(func(i) - avg, 2.);
798  var /= (double(BOOT_BINS) - 1);
799  return pair<double, double>(var, var);
800  }
801 
802  // @brief Calculate the bootstrapped sample envelope for the observable
803  // given by correlators and the transformation @parm func.
804  template<typename T>
805  static pair<double, double> sampleEnvelope(T func) {
806  // First we calculate the mean.
807  double avg = 0.;
808  for (int i = 0; i < BOOT_BINS; ++i) avg += func(i);
809  avg /= double(BOOT_BINS);
810  double yMax = avg;
811  double yMin = avg;
812  // Then we find the envelope using the mean as initial value.
813  for (int i = 0; i < BOOT_BINS; ++i) {
814  double yVal = func(i);
815  if (yMin > yVal) yMin = yVal;
816  else if (yMax < yVal) yMax = yVal;
817  }
818  return pair<double, double>(fabs(avg - yMin), fabs(yMax - avg));
819  }
820 
821  // @brief Selection method for which sample error to use, given
822  // in the constructor.
823  template<typename T>
824  const pair<double, double> sampleError(T func) const {
825  if (errorMethod == VARIANCE) return sampleVariance(func);
826  else if (errorMethod == ENVELOPE) return sampleEnvelope(func);
827  else
828  cout << "Error: Error method not found!" << endl;
829  return pair<double, double>(0.,0.);
830  }
831 
832  // @brief Two particle integrated cn.
833  const void cnTwoInt(Scatter2DPtr h, ECorrPtr e2) const {
834  vector<CorBin> bins = e2->getBins();
835  vector<double> binx = e2->getBinX();
836  // Assert bin size.
837  if (binx.size() - 1 != bins.size()){
838  cout << "cnTwoInt: Bin size (x,y) differs!" << endl;
839  return;
840  }
841  vector<CorBinBase*> binPtrs;
842  // The mean value of the cumulant.
843  auto cn = [&] (int i) { return binPtrs[i]->mean(); };
844  // Error calculation.
845  vector<pair<double, double> > yErr;
846  for (int j = 0, N = bins.size(); j < N; ++j) {
847  binPtrs = bins[j].getBinPtrs();
848  yErr.push_back(sampleError(cn));
849  }
850  binPtrs = e2->getBinPtrs();
851  fillScatter(h, binx, cn, yErr);
852  }
853 
854  // @brief Two particle integrated vn.
855  const void vnTwoInt(Scatter2DPtr h, ECorrPtr e2) const {
856  cnTwoInt(h, e2);
857  nthPow(h, 0.5);
858  }
859 
860  // @brief Put an event averaged correlator into a Scatter2D.
861  // Reduces to cnTwoInt, but better with a proper name.
862  const void corrPlot(Scatter2DPtr h, ECorrPtr e) const {
863  cnTwoInt(h, e);
864  }
865 
866  // @brief Put an event averaged correlator into Profile1Ds, one
867  // for each bootstrapping bin.
868  const void corrPlot(list<Profile1DPtr> profs, ECorrPtr e) const {
869  vector<CorBin> corBins = e->getBins();
870  vector<double> binx = e->getBinX();
871  auto ref = e->getReference();
872  auto refBins = ref.getBinPtrs<CorSingleBin>();
873  // Assert bin size.
874  if (binx.size() - 1 != corBins.size()){
875  cout << "corrPlot: Bin size (x,y) differs!" << endl;
876  return;
877  }
878  list<Profile1DPtr>::iterator hItr = profs.begin();
879  // Loop over the boostrapped correlators.
880  for (size_t i = 0; i < profs.size(); ++i, ++hItr) {
881  vector<YODA::ProfileBin1D> profBins;
882  // Numbers for the summary distribution
883  double ne = 0., sow = 0., sow2 = 0.;
884  for (size_t j = 0, N = binx.size() - 1; j < N; ++j) {
885  vector<CorSingleBin*> binPtrs =
886  corBins[j].getBinPtrs<CorSingleBin>();
887  // Construct bin of the profiled quantities. We have no information
888  // (and no desire to add it) of sumWX of the profile, so really
889  // we should use a Dbn1D - but that does not work for Profile1D's.
890  profBins.push_back( YODA::ProfileBin1D((*hItr)->bin(j).xEdges(),
891  YODA::Dbn2D( binPtrs[i]->numEntries(), binPtrs[i]->sumW(),
892  binPtrs[i]->sumW2(), 0., 0., binPtrs[i]->sumWX(), 0, 0)));
893  ne += binPtrs[i]->numEntries();
894  sow += binPtrs[i]->sumW();
895  sow2 += binPtrs[i]->sumW2();
896  }
897  // Reset the bins of the profiles.
898  (*hItr)->reset();
899  (*hItr)->bins().clear();
900  // Add our new bins.
901  // The total distribution
902  (*hItr)->setTotalDbn(YODA::Dbn2D(ne,sow,sow2,0.,0.,0.,0.,0.));
903  // The bins.
904  for (int j = 0, N = profBins.size(); j < N; ++j)
905  (*hItr)->addBin(profBins[j]);
906  // The reference flow in the underflow bin.
907  (*hItr)->setUnderflow(YODA::Dbn2D(refBins[i]->numEntries(),
908  refBins[i]->sumW(), refBins[i]->sumW2(), 0., 0.,
909  refBins[i]->sumWX(), 0., 0.));
910  } // End loop of bootstrapped correlators.
911  }
912  // @brief Four particle integrated cn.
913  const void cnFourInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4) const {
914  auto e2bins = e2->getBins();
915  auto e4bins = e4->getBins();
916  auto binx = e2->getBinX();
917  if (binx.size() - 1 != e2bins.size()){
918  cout << "cnFourInt: Bin size (x,y) differs!" << endl;
919  return;
920  }
921  if (binx != e4->getBinX()) {
922  cout << "Error in cnFourInt: Correlator x-binning differs!" << endl;
923  return;
924  }
925  vector<CorBinBase*> e2binPtrs;
926  vector<CorBinBase*> e4binPtrs;
927  auto cn = [&] (int i) {
928  double e22 = e2binPtrs[i]->mean() * e2binPtrs[i]->mean();
929  return e4binPtrs[i]->mean() - 2. * e22;
930  };
931  // Error calculation.
932  vector<pair<double, double> > yErr;
933  for (int j = 0, N = e2bins.size(); j < N; ++j) {
934  e2binPtrs = e2bins[j].getBinPtrs();
935  e4binPtrs = e4bins[j].getBinPtrs();
936  yErr.push_back(sampleError(cn));
937  }
938  // Put the bin ptrs back in place.
939  e2binPtrs = e2->getBinPtrs();
940  e4binPtrs = e4->getBinPtrs();
941  fillScatter(h, binx, cn, yErr);
942  }
943 
944  // @brief Four particle integrated vn
945  const void vnFourInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4) const {
946  cnFourInt(h, e2, e4);
947  nthPow(h, 0.25, -1.0);
948  }
949 
950  // @brief Six particle integrated cn.
951  const void cnSixInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4,
952  ECorrPtr e6) const {
953  auto e2bins = e2->getBins();
954  auto e4bins = e4->getBins();
955  auto e6bins = e6->getBins();
956  auto binx = e2->getBinX();
957  if (binx.size() - 1 != e2bins.size()){
958  cout << "cnSixInt: Bin size (x,y) differs!" << endl;
959  return;
960  }
961  if (binx != e4->getBinX() || binx != e6->getBinX()) {
962  cout << "Error in cnSixInt: Correlator x-binning differs!" << endl;
963  return;
964  }
965  vector<CorBinBase*> e2binPtrs;
966  vector<CorBinBase*> e4binPtrs;
967  vector<CorBinBase*> e6binPtrs;
968  auto cn = [&] (int i) {
969  double e23 = pow(e2binPtrs[i]->mean(), 3.0);
970  return e6binPtrs[i]->mean() - 9.*e2binPtrs[i]->mean()*e4binPtrs[i]->mean() +
971  12.*e23;
972  };
973  // Error calculation.
974  vector<pair<double, double> > yErr;
975  for (int j = 0, N = e2bins.size(); j < N; ++j) {
976  e2binPtrs = e2bins[j].getBinPtrs();
977  e4binPtrs = e4bins[j].getBinPtrs();
978  e6binPtrs = e6bins[j].getBinPtrs();
979  yErr.push_back(sampleError(cn));
980  }
981  // Put the bin ptrs back in place.
982  e2binPtrs = e2->getBinPtrs();
983  e4binPtrs = e4->getBinPtrs();
984  e6binPtrs = e6->getBinPtrs();
985  fillScatter(h, binx, cn, yErr);
986  }
987 
988  // @brief Six particle integrated vn
989  const void vnSixInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4,
990  ECorrPtr e6) const {
991  cnSixInt(h, e2, e4, e6);
992  nthPow(h, 1./6., 0.25);
993  }
994 
995  // @brief Eight particle integrated cn.
996  const void cnEightInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4,
997  ECorrPtr e6, ECorrPtr e8) const {
998  auto e2bins = e2->getBins();
999  auto e4bins = e4->getBins();
1000  auto e6bins = e6->getBins();
1001  auto e8bins = e8->getBins();
1002  auto binx = e2->getBinX();
1003  if (binx.size() - 1 != e2bins.size()){
1004  cout << "cnEightInt: Bin size (x,y) differs!" << endl;
1005  return;
1006  }
1007  if (binx != e4->getBinX() || binx != e6->getBinX() ||
1008  binx != e8->getBinX()) {
1009  cout << "Error in cnEightInt: Correlator x-binning differs!" << endl;
1010  return;
1011  }
1012  vector<CorBinBase*> e2binPtrs;
1013  vector<CorBinBase*> e4binPtrs;
1014  vector<CorBinBase*> e6binPtrs;
1015  vector<CorBinBase*> e8binPtrs;
1016  auto cn = [&] (int i ) {
1017  double e22 = e2binPtrs[i]->mean() * e2binPtrs[i]->mean();
1018  double e24 = e22 * e22;
1019  double e42 = e4binPtrs[i]->mean() * e4binPtrs[i]->mean();
1020  return e8binPtrs[i]->mean() - 16. * e6binPtrs[i]->mean() *
1021  e2binPtrs[i]->mean() - 18. * e42 + 144. * e4binPtrs[i]->mean()*e22
1022  - 144. * e24;
1023  };
1024  // Error calculation.
1025  vector<pair<double, double> > yErr;
1026  for (int j = 0, N = e2bins.size(); j < N; ++j) {
1027  e2binPtrs = e2bins[j].getBinPtrs();
1028  e4binPtrs = e4bins[j].getBinPtrs();
1029  e6binPtrs = e6bins[j].getBinPtrs();
1030  e8binPtrs = e8bins[j].getBinPtrs();
1031  yErr.push_back(sampleError(cn));
1032  }
1033  // Put the bin ptrs back in place.
1034  e2binPtrs = e2->getBinPtrs();
1035  e4binPtrs = e4->getBinPtrs();
1036  e6binPtrs = e6->getBinPtrs();
1037  e8binPtrs = e8->getBinPtrs();
1038  fillScatter(h, binx, cn, yErr);
1039  }
1040 
1041  // @brief Eight particle integrated vn
1042  const void vnEightInt(Scatter2DPtr h, ECorrPtr e2, ECorrPtr e4,
1043  ECorrPtr e6, ECorrPtr e8) const {
1044  cnEightInt(h, e2, e4, e6, e8);
1045  nthPow(h, 1./8., -1./33.);
1046  }
1047 
1048  // @brief Two particle differential vn.
1049  const void vnTwoDiff(Scatter2DPtr h, ECorrPtr e2Dif) const {
1050  auto e2bins = e2Dif->getBins();
1051  auto ref = e2Dif->getReference();
1052  auto binx = e2Dif->getBinX();
1053  if (binx.size() -1 != e2bins.size()) {
1054  cout << "vnTwoDif: Bin size (x,y) differs!" << endl;
1055  return;
1056  }
1057  vector<CorBinBase*> e2binPtrs;
1058  vector<CorBinBase*> refPtrs;
1059  auto vn = [&] (int i) {
1060  // Test reference flow.
1061  if (ref.mean() <= 0) return 0.;
1062  return e2binPtrs[i]->mean() / sqrt(ref.mean());
1063  };
1064  // We need here a seperate error function, as we don't
1065  // iterate over the reference flow.
1066  auto vnerr = [&] (int i) {
1067  // Test reference flow.
1068  if (refPtrs[i]->mean() <=0) return 0.;
1069  return e2binPtrs[i]->mean() / sqrt(refPtrs[i]->mean());
1070  };
1071  // Error calculation.
1072  vector<pair<double, double> > yErr;
1073  refPtrs = ref.getBinPtrs();
1074  for (int j = 0, N = e2bins.size(); j < N; ++j) {
1075  e2binPtrs = e2bins[j].getBinPtrs();
1076  yErr.push_back(sampleError(vnerr));
1077  }
1078  // Put the e2binPtrs back in place.
1079  e2binPtrs = e2Dif->getBinPtrs();
1080  fillScatter(h, binx, vn);
1081  }
1082 
1083  // @brief Four particle differential vn.
1084  const void vnFourDiff(Scatter2DPtr h, ECorrPtr e2Dif,
1085  ECorrPtr e4Dif) const {
1086  auto e2bins = e2Dif->getBins();
1087  auto e4bins = e4Dif->getBins();
1088  auto ref2 = e2Dif->getReference();
1089  auto ref4 = e4Dif->getReference();
1090  auto binx = e2Dif->getBinX();
1091  if (binx.size() - 1 != e2bins.size()){
1092  cout << "vnFourDif: Bin size (x,y) differs!" << endl;
1093  return;
1094  }
1095  if (binx != e4Dif->getBinX()) {
1096  cout << "Error in vnFourDif: Correlator x-binning differs!" << endl;
1097  return;
1098  }
1099  vector<CorBinBase*> e2binPtrs;
1100  vector<CorBinBase*> e4binPtrs;
1101  vector<CorBinBase*> ref2Ptrs;
1102  vector<CorBinBase*> ref4Ptrs;
1103  double denom = 2 * ref2.mean() * ref2.mean() - ref4.mean();
1104  auto vn = [&] (int i) {
1105  // Test denominator.
1106  if (denom <= 0 ) return 0.;
1107  return ((2 * ref2.mean() * e2bins[i].mean() - e4bins[i].mean()) /
1108  pow(denom, 0.75));
1109  };
1110  // We need here a seperate error function, as we don't
1111  // iterate over the reference flow.
1112  auto vnerr = [&] (int i) {
1113  double denom2 = 2 * ref2Ptrs[i]->mean() * ref2Ptrs[i]->mean() -
1114  ref4Ptrs[i]->mean();
1115  // Test denominator.
1116  if (denom2 <= 0) return 0.;
1117  return ((2 * ref2Ptrs[i]->mean() * e2binPtrs[i]->mean() -
1118  e4binPtrs[i]->mean()) / pow(denom2, 0.75));
1119  };
1120  // Error calculation.
1121  vector<pair<double, double> > yErr;
1122  ref2Ptrs = ref2.getBinPtrs();
1123  ref4Ptrs = ref4.getBinPtrs();
1124  for (int j = 0, N = e2bins.size(); j < N; ++j) {
1125  e2binPtrs = e2bins[j].getBinPtrs();
1126  e4binPtrs = e4bins[j].getBinPtrs();
1127  yErr.push_back(sampleError(vnerr));
1128  }
1129  // Put the binPtrs back in place.
1130  e2binPtrs = e2Dif->getBinPtrs();
1131  e4binPtrs = e4Dif->getBinPtrs();
1132  fillScatter(h, binx, vn, yErr);
1133  }
1134  }; // End class CumulantAnalysis.
1135 } // End Rivet namespace.
1136 #endif
Definition: ALICE_2010_I880049.cc:13
const vector< int > getH1() const
Get a copy of the h1 harmonic vector.
Definition: Correlators.hh:472
std::enable_if< std::is_arithmetic< NUM1 >::value &&std::is_arithmetic< NUM2 >::value, int >::type binIndex(NUM1 val, std::initializer_list< NUM2 > binedges, bool allow_overflow=false)
Return the bin index of the given value, val, given a vector of bin edges.
Definition: MathUtils.hh:356
void fillFromProfs()
Fill bins with content from preloaded histograms.
Definition: Correlators.hh:503
const vector< double > getBinX() const
Get a copy of the bin x-values.
Definition: Correlators.hh:467
const vector< pair< double, double > > pTBinnedCorrelators(vector< int > n, bool overflow=false) const
pT differential correlator of n harmonic, with the number of powers being the size of n...
Definition: Correlators.cc:63
static vector< int > hVec(int n, int m)
Construct a harmonic vectors from n harmonics and m number of particles. TODO: In C++14 this can be...
Definition: Correlators.hh:108
void fill(const Correlators &c1, const Correlators &c2, const double &weight=1.0)
Fill bins with the appropriate correlator, taking the binning directly from the Correlators object...
Definition: Correlators.hh:434
const vector< int > getH2() const
Get a copy of the h2 harmonic vector.
Definition: Correlators.hh:477
ECorrelator(vector< int > h1In, vector< int > h2In, vector< double > binIn)
Constructor for gapped correlator. Takes as argument the desired harmonics for the two final states...
Definition: Correlators.hh:387
Particle representation, either from a HepMC::GenEvent or reconstructed.
Definition: Particle.hh:18
The ECorrelator is a helper class to calculate all event averages of correlators, in order to constru...
Definition: Correlators.hh:368
const pair< double, double > intCorrelatorGap(const Correlators &other, vector< int > n1, vector< int > n2) const
Integrated correlator of n1 harmonic, with the number of powers being the size of n1...
Definition: Correlators.cc:88
static constexpr double DBL_NAN
Convenient const for getting the double NaN value.
Definition: Utils.hh:54
Base class for projections which return subsets of an event&#39;s particles.
Definition: ParticleFinder.hh:11
Tools for flow analyses. The following are helper classes to construct event averaged correlators as ...
Definition: Correlators.hh:218
void fill(const Correlators &c, const double &weight=1.0)
Fill the bins with the appropriate correlator, taking the binning directly from the Correlators objec...
Definition: Correlators.hh:418
void setReference(CorBin refIn)
Replace reference flow bin with another reference flow bin, eg. calculated in another phase space or ...
Definition: Correlators.hh:484
const vector< pair< double, double > > pTBinnedCorrelatorsGap(const Correlators &other, vector< int > n1, vector< int > n2, bool oveflow=false) const
pT differential correlators of n1 harmonic, with the number of powers being the size of n1...
Definition: Correlators.cc:113
This is the base class of all analysis classes in Rivet.
Definition: Analysis.hh:52
Definition: Event.hh:22
void fill(const double &obs, const Correlators &c1, const Correlators &c2, const double weight=1.0)
Fill the appropriate bin given an input (per event) observable, eg. centrality. Using a rapidity gap ...
Definition: Correlators.hh:403
Cmp< Projection > mkPCmp(const Projection &otherparent, const std::string &pname) const
Definition: Projection.cc:55
static pair< int, int > getMaxValues(vector< vector< int > > &hList)
Return the maximal values for n, p to be used in the constructor of Correlators(xxx, nMax, pMax, xxxx)
Definition: Correlators.hh:124
list< Profile1DPtr >::iterator profEnd()
end() iterator for the list of associated profile histograms.
Definition: Correlators.hh:527
static void nthPow(Scatter2DPtr h, const double &n, const double &k=1.0)
Take the n th power of all points in h, and put the result back in the same Scatter2D. Optionally put a k constant below the root.
Definition: Correlators.hh:757
int compare(const Projection &p) const
Definition: Correlators.hh:148
const vector< CorBin > getBins() const
Get a copy of the bin contents.
Definition: Correlators.hh:454
virtual std::string name() const
Get the name of the projection.
Definition: Projection.hh:56
Definition: Correlators.hh:39
void project(const Event &e)
Definition: Correlators.cc:149
list< Profile1DPtr >::iterator profBegin()
begin() iterator for the list of associated profile histograms.
Definition: Correlators.hh:522
const pair< double, double > intCorrelator(vector< int > n) const
Integrated correlator of n harmonic, with the number of powers being the size of n...
Definition: Correlators.cc:49
static void nthPow(Scatter2DPtr hOut, const Scatter2DPtr hIn, const double &n, const double &k=1.0)
Take the n th power of all points in hIn, and put the result in hOut. Optionally put a k constant...
Definition: Correlators.hh:719
void setProfs(list< Profile1DPtr > prIn)
set the prIn list of profile histograms associated with the internal bins. Is called automatically w...
Definition: Correlators.hh:498
ECorrelator(vector< int > h, vector< double > binIn)
Constructor. Takes as argument the desired harmonic and number of correlated particles as a generic f...
Definition: Correlators.hh:382
Base class for all Rivet projections.
Definition: Projection.hh:29
std::enable_if< std::is_arithmetic< NUM >::value, double >::type mean(const vector< NUM > &sample)
Definition: MathUtils.hh:398
void fill(const double &obs, const Correlators &c, const double weight=1.0)
Fill the appropriate bin given an input (per event) observable, eg. centrality.
Definition: Correlators.hh:393
const CorBin getReference() const
Extract the reference flow from a differential event averaged correlator.
Definition: Correlators.hh:490