Rivet API documentation

Rivet 4.1.3
CentralityBinner.hh
1// -*- C++ -*-
2#ifndef RIVET_CENTRALITYBINNER_HH
3#define RIVET_CENTRALITYBINNER_HH
4#include "Rivet/Config/RivetCommon.hh"
5#include "Rivet/Projections/HepMCHeavyIon.hh"
6#include "Rivet/Tools/RivetYODA.hh"
7#include <tuple>
8
9namespace Rivet {
10
11
35 public:
36
39 : _estimate(-1.0) {
40 setName("CentralityEstimator");
41 declare(HepMCHeavyIon(), "HepMC");
42 }
43
46
47 protected:
48
50 void project(const Event& e) {
51 _estimate = -1.0;
52 double imp = apply<HepMCHeavyIon>(e, "HepMC").impact_parameter();
53 if (imp < 0.0) return;
54 _estimate = imp > 0.0 ? 1.0 / imp : numeric_limits<double>::max();
55 }
56
58 CmpState compare(const Projection& p) const {
59 return mkNamedPCmp(p, "HepMC");
60 }
61
62
63 public:
64
66 double estimate() const {
67 return _estimate;
68 }
69
70
71 protected:
72
74 double _estimate;
75 };
76
77
81 template <typename T>
82 struct CentralityBinTraits {
83
85 static T clone(const T& t) {
86 return T(t->newclone());
87 }
88
90 static void add(T& t, const T& o) {
91 *t += *o;
92 }
93
95 static void scale(T& t, double f) {
96 t->scaleW(f);
97 }
98
101 static void normalize(T& t, double sumw) {
102 if (t->sumW() > 0.0) t->normalize(t->sumW() / sumw);
103 }
104
106 static string path(T t) {
107 return t->path();
108 }
109 };
110
114 struct MergeDistance {
115
125 static double dist(double cestLo, double cestHi, double weight, double clo, double chi, double, double) {
126 return (cestHi - cestLo) * weight / (cestHi * (chi - clo));
127 }
128 };
129
130
138 template <typename T = Histo1DPtr, typename MDist = MergeDistance>
140 public:
141
146 CentralityBinner(int maxbins = 200, double wlim = 0.02)
147 : _currentCEst(-1.0), _maxBins(maxbins), _warnlimit(wlim), _weightsum(0.0) {
148 _percentiles.insert(0.0);
149 _percentiles.insert(1.0);
150 }
151
154 void setProjection(const CentralityEstimator& p, string pname) {
155 declare(p, pname);
156 _estimator = pname;
157 }
158
160 virtual std::string name() const {
161 return "Rivet::CentralityBinner";
162 }
163
168
172
175
176 void add(T t, double cmin, double cmax, double cestmin = -1.0, double cestmax = -1.0) {
177 _percentiles.insert(max(1.0 - cmax / 100.0, 0.0));
178 _percentiles.insert(min(1.0 - cmin / 100.0, 1.0));
179 if (_unfilled.empty() && _ready.empty()) _devnull = CentralityBinTraits<T>::clone(t);
180 if (cestmin < 0.0)
181 _unfilled.push_back(Bin(t, 1.0 - cmax / 100.0, 1.0 - cmin / 100.0));
182 else
183 _ready[t] = Bin(t, 1.0 - cmax / 100.0, 1.0 - cmin / 100.0, cestmin, cestmax);
184 }
185
194 T select(const Event& event, double weight = 1.0) {
195 return select(applyProjection<CentralityEstimator>(event, _estimator).estimate(), weight);
196 }
197
204 T select(double cest, double weight = 1.0);
205
212 void finalize();
213
217 for (auto& b : _ready) b.second.normalizePerEvent();
218 }
219
222 map<double, double> edges() const {
223 map<double, double> ret;
224 for (auto& b : _ready) {
225 ret[1.0 - b.second._centLo] = b.second._cestLo;
226 ret[1.0 - b.second._centHi] = b.second._cestHi;
227 }
228 return ret;
229 }
230
232 const T& current() const {
233 return _currenT;
234 }
235
238 double estimator() const {
239 return _currentCEst;
240 }
241
242 vector<T> allObjects() {
243 vector<T> ret;
244 for (auto& fb : _flexiBins) ret.push_back(fb._t);
245 if (!ret.empty()) return ret;
246 for (auto b : _ready) ret.push_back(b.second._t);
247 return ret;
248 }
249
250 private:
251
253 struct FlexiBin {
254
257 FlexiBin(T& t, double cest = 0.0, double weight = 0.0)
258 : _t(t), _cestLo(cest), _cestHi(cest), _weightsum(weight), _n(1), _m(0) { }
259
261 FlexiBin(double cest)
262 : _cestLo(cest), _cestHi(cest), _weightsum(0.0), _n(0), _m(0) { }
263
265 void merge(const FlexiBin& fb) {
266 _cestLo = min(_cestLo, fb._cestLo);
267 _cestHi = max(_cestHi, fb._cestHi);
268 _weightsum += fb._weightsum;
269 CentralityBinTraits<T>::add(_t, fb._t);
270 _n += fb._n;
271 _m += fb._m + 1;
272 }
273
275 bool operator<(const FlexiBin& fb) const {
276 return _cestLo < fb._cestLo;
277 }
278
281 bool inRange(double cest) const {
282 return cest == _cestLo || (_cestLo < cest && cest < _cestHi);
283 }
284
286 T _t;
287
290 double _cestLo, _cestHi;
291
294 mutable double _weightsum;
295
297 mutable int _n;
298
300 mutable int _m;
301 };
302
303 struct Bin {
304
306 Bin()
307 : _centLo(-1.0),
308 _centHi(-1.0),
309 _cestLo(-1.0),
310 _cestHi(-1.0),
311 _weightsum(0.0),
312 _underflow(0.0),
313 _overflow(0.0),
314 _ambiguous(0),
315 _ambweight(0.0) { }
316
321 Bin(T t, double centLo, double centHi, double cestLo = -1.0, double cestHi = -1.0)
322 : _t(t),
323 _centLo(centLo),
324 _centHi(centHi),
325 _cestLo(cestLo),
326 _cestHi(cestHi),
327 _weightsum(0.0),
328 _underflow(0.0),
329 _overflow(0.0),
330 _ambiguous(0.0),
331 _ambweight(0.0) { }
332
335 bool inRange(double cest) const {
336 return _cestLo >= 0 && _cestLo <= cest && (_cestHi < 0.0 || cest <= _cestHi);
337 }
338
340 void normalizePerEvent() {
341 CentralityBinTraits<T>::normalize(_t, _weightsum);
342 }
343
345 T _t;
346
348 double _centLo, _centHi;
349
351 double _cestLo, _cestHi;
352
354 double _weightsum;
355
358 double _underflow;
359
362 double _overflow;
363
365 double _ambiguous;
366
368 double _ambweight;
369 };
370
371 protected:
372
374 typedef set<FlexiBin> FlexiBinSet;
375
378 typename FlexiBinSet::iterator _findBin(double cest) {
379 if (_flexiBins.empty()) return _flexiBins.end();
380 auto it = _flexiBins.lower_bound(FlexiBin(cest));
381 if (it->_cestLo == cest) return it;
382 if (it != _flexiBins.begin()) --it;
383 if (it->_cestLo < cest && cest < it->_cestHi) return it;
384 return _flexiBins.end();
385 }
386
388 string _estimator;
389
392 T _currenT;
393
395 double _currentCEst;
396
399 int _maxBins;
400
403 double _warnlimit;
404
407 vector<Bin> _unfilled;
408
410 FlexiBinSet _flexiBins;
411
413 double _weightsum;
414
416 set<double> _percentiles;
417
419 map<T, Bin> _ready;
420
423 T _devnull;
424
425 public:
426
428 void debug();
429 void fulldebug();
430 };
431
432
434 template <>
435 struct CentralityBinTraits<Profile1DPtr> {
436
437 typedef Profile1DPtr T;
438
440 static T clone(const T& t) {
441 return Profile1DPtr(t->newclone());
442 }
443
445 static void add(T& t, const T& o) {
446 *t += *o;
447 }
448
450 static void scale(T& t, double f) {
451 t->scaleW(f);
452 }
453
454 static void normalize(T& t, double sumw) { }
455
457 static string path(T t) {
458 return t->path();
459 }
460 };
461
462
464 template <>
465 struct CentralityBinTraits<Profile2DPtr> {
466
467 typedef Profile2DPtr T;
468
470 static T clone(const T& t) {
471 return Profile2DPtr(t->newclone());
472 }
473
475 static void add(T& t, const T& o) {
476 *t += *o;
477 }
478
480 static void scale(T& t, double f) {
481 t->scaleW(f);
482 }
483
484 static void normalize(T& t, double sumw) { }
485
487 static string path(T t) {
488 return t->path();
489 }
490 };
491
492 template <typename T>
493 struct CentralityBinTraits<vector<T>> {
494
496 static vector<T> clone(const vector<T>& tv) {
497 vector<T> rtv;
498 for (auto t : tv) rtv.push_back(CentralityBinTraits<T>::clone(t));
499 return rtv;
500 }
501
503 static void add(vector<T>& tv, const vector<T>& ov) {
504 for (int i = 0, N = tv.size(); i < N; ++i) CentralityBinTraits::add(tv[i], ov[i]);
505 }
506
508 static void scale(vector<T>& tv, double f) {
509 for (auto t : tv) CentralityBinTraits<T>::scale(t, f);
510 }
511
512 static void normalize(vector<T>& tv, double sumw) {
513 for (auto t : tv) CentralityBinTraits<T>::normalize(t, sumw);
514 }
515
517 static string path(const vector<T>& tv) {
518 string ret = "(vector:";
519 for (auto t : tv) {
520 ret += " ";
521 ret += CentralityBinTraits<T>::path(t);
522 }
523 ret += ")";
524 return ret;
525 }
526 };
527
528 template <size_t I, typename... Types>
529 struct TupleCentralityBinTraitsHelper {
530
531 typedef tuple<Types...> Tuple;
532 typedef typename tuple_element<I - 1, Tuple>::type T;
533
534 static void clone(Tuple& ret, const Tuple& tup) {
535 get<I - 1>(ret) = CentralityBinTraits<T>::clone(get<I - 1>(tup));
536 TupleCentralityBinTraitsHelper<I - 1, Types...>::clone(ret, tup);
537 }
538
539 static void add(Tuple& tup, const Tuple& otup) {
540 CentralityBinTraits<T>::add(get<I - 1>(tup), get<I - 1>(otup));
541 TupleCentralityBinTraitsHelper<I - 1, Types...>::add(tup, otup);
542 }
543
544 static void scale(Tuple& tup, double f) {
545 CentralityBinTraits<T>::scale(get<I - 1>(tup), f);
546 TupleCentralityBinTraitsHelper<I - 1, Types...>::scale(tup, f);
547 }
548
549 static void normalize(Tuple& tup, double sumw) {
550 CentralityBinTraits<T>::normalize(get<I - 1>(tup), sumw);
551 TupleCentralityBinTraitsHelper<I - 1, Types...>::normalize(tup, sumw);
552 }
553
554 static string path(const Tuple& tup) {
555 return " " + CentralityBinTraits<T>::path(get<I - 1>(tup))
556 + TupleCentralityBinTraitsHelper<I - 1, Types...>::path(tup);
557 }
558 };
559
560 template <typename... Types>
561 struct TupleCentralityBinTraitsHelper<0, Types...> {
562
563 typedef tuple<Types...> Tuple;
564
565 static void clone(Tuple&, const Tuple&) { }
566 static void add(Tuple& tup, const Tuple& otup) { }
567 static void scale(Tuple& tup, double f) { }
568 static void normalize(Tuple& tup, double sumw) { }
569 static string path(const Tuple& tup) {
570 return "";
571 }
572 };
573
574 template <typename... Types>
575 struct CentralityBinTraits<tuple<Types...>> {
576
577 typedef tuple<Types...> Tuple;
578 static const size_t N = tuple_size<Tuple>::value;
579
581 static Tuple clone(const Tuple& tup) {
582 Tuple ret;
583 TupleCentralityBinTraitsHelper<N, Types...>::clone(ret, tup);
584 return ret;
585 }
586
588 static void add(Tuple& tup, const Tuple& otup) {
589 TupleCentralityBinTraitsHelper<N, Types...>::add(tup, otup);
590 }
591
593 static void scale(Tuple& tup, double f) {
594 TupleCentralityBinTraitsHelper<N, Types...>::scale(tup, f);
595 }
596
597 static void normalize(Tuple& tup, double sumw) {
598 TupleCentralityBinTraitsHelper<N, Types...>::normalize(tup, sumw);
599 }
600
602 static string path(const Tuple& tup) {
603 string ret = "(tuple:";
604 ret += TupleCentralityBinTraitsHelper<N, Types...>::path(tup);
605 ret += ")";
606 return ret;
607 }
608 };
609
610 template <typename T, typename MDist>
611 T CentralityBinner<T, MDist>::select(double cest, double weight) {
612 _currenT = _devnull;
613 _currentCEst = cest;
614 _weightsum += weight;
615
616 // If estimator is negative, something has gone wrong.
617 if (_currentCEst < 0.0) return _currenT;
618
619 // If we already have finalized the limits on the centrality
620 // estimator, we just add the weights to their bins and return the
621 // corresponding AnalysisObject.
622 if (_unfilled.empty()) {
623 for (auto& b : _ready)
624 if (b.second.inRange(_currentCEst)) {
625 b.second._weightsum += weight;
626 return b.second._t;
627 }
628 return _currenT;
629 }
630
631 auto it = _findBin(cest);
632 if (it == _flexiBins.end()) {
633 _currenT = CentralityBinTraits<T>::clone(_unfilled.begin()->_t);
634 it = _flexiBins.insert(FlexiBin(_currenT, _currentCEst, weight)).first;
635 }
636 else {
637 it->_weightsum += weight;
638 ++(it->_n);
639 _currenT = it->_t;
640 }
641
642 if ((int)_flexiBins.size() <= _maxBins) return _currenT;
643
644
645 set<double>::iterator citn = _percentiles.begin();
646 set<double>::iterator cit0 = citn++;
647 auto selectit = _flexiBins.end();
648 double mindist = -1.0;
649 double acc = 0.0;
650 auto next = _flexiBins.begin();
651 auto prev = next++;
652 for (; next != _flexiBins.end(); prev = next++) {
653 acc += prev->_weightsum / _weightsum;
654 if (acc > *citn) {
655 cit0 = citn++;
656 continue;
657 }
658 if (acc + next->_weightsum / _weightsum > *citn) continue;
659 double dist = MDist::dist(prev->_cestLo, next->_cestHi, next->_weightsum + prev->_weightsum, *cit0,
660 *citn, next->_n + prev->_n, next->_m + prev->_m);
661 if (mindist < 0.0 || dist < mindist) {
662 selectit = prev;
663 mindist = dist;
664 }
665 }
666
667 if (selectit == _flexiBins.end()) return _currenT;
668 auto mergeit = selectit++;
669 FlexiBin merged = *mergeit;
670 merged.merge(*selectit);
671 if (merged.inRange(cest) || selectit->inRange(cest)) _currenT = merged._t;
672 _flexiBins.erase(mergeit);
673 _flexiBins.erase(selectit);
674 _flexiBins.insert(merged);
675
676 return _currenT;
677 }
678
679
680 template <typename T, typename MDist>
682
683 // Take the contents of the dynamical binning and fill the original
684 // AnalysisObjects.
685
686 double clo = 0.0;
687 for (const FlexiBin& fb : _flexiBins) {
688 double chi = min(clo + fb._weightsum / _weightsum, 1.0);
689 for (Bin& bin : _unfilled) {
690 double olo = bin._centLo;
691 double ohi = bin._centHi;
692 if (clo > ohi || chi <= olo) continue;
693 // If we only have partial overlap we need to scale
694 double lo = max(olo, clo);
695 double hi = min(ohi, chi);
696 T t = CentralityBinTraits<T>::clone(fb._t);
697 double frac = (hi - lo) / (chi - clo);
698 CentralityBinTraits<T>::scale(t, frac);
699 CentralityBinTraits<T>::add(bin._t, t);
700 bin._weightsum += fb._weightsum * frac;
701 if (clo <= olo) bin._cestLo = fb._cestLo + (fb._cestHi - fb._cestLo) * (olo - clo) / (chi - clo);
702 if (clo < olo) {
703 bin._underflow = clo;
704 bin._ambiguous += fb._n * frac;
705 bin._ambweight += fb._weightsum * frac * (1.0 - frac);
706 }
707 if (chi > ohi) {
708 bin._cestHi = fb._cestLo + (fb._cestHi - fb._cestLo) * (ohi - clo) / (chi - clo);
709 bin._overflow = chi;
710 bin._ambiguous += fb._n * frac;
711 bin._ambweight += fb._weightsum * frac * (1.0 - frac);
712 }
713 }
714 clo = chi;
715 }
716 _flexiBins.clear();
717 for (Bin& bin : _unfilled) {
718 if (bin._overflow == 0.0) bin._overflow = 1.0;
719 _ready[bin._t] = bin;
720 if (bin._ambweight / bin._weightsum > _warnlimit)
721 MSG_WARNING("Analysis object \""
722 << CentralityBinTraits<T>::path(bin._t)
723 << "\", contains events with centralities between " << bin._underflow * 100.0 << " and "
724 << bin._overflow * 100.0 << "% (" << int(bin._ambiguous + 0.5)
725 << " ambiguous events with effectively " << 100.0 * bin._ambweight / bin._weightsum
726 << "% of the weights)."
727 << "Consider increasing the number of bins.");
728 }
729 _unfilled.clear();
730 }
731
732 template <typename T, typename MDist>
733 void CentralityBinner<T, MDist>::fulldebug() {
734 cerr << endl;
735 double acc = 0.0;
736 set<double>::iterator citn = _percentiles.begin();
737 set<double>::iterator cit0 = citn++;
738 int i = 0;
739 for (auto it = _flexiBins.begin(); it != _flexiBins.end();) {
740 ++i;
741 auto curr = it++;
742 double w = curr->_weightsum / _weightsum;
743 acc += w;
744 if (curr == _flexiBins.begin() || it == _flexiBins.end() || acc > *citn)
745 cerr << "*";
746 else
747 cerr << " ";
748 if (acc > *citn) cit0 = citn++;
749 cerr << setw(6) << i << setw(12) << acc - w << setw(12) << acc << setw(8) << curr->_n << setw(8)
750 << curr->_m << setw(12) << curr->_cestLo << setw(12) << curr->_cestHi << endl;
751 }
752 cerr << "Number of sampler bins: " << _flexiBins.size() << endl;
753 }
754
755 template <typename T, typename MDist>
757 cerr << endl;
758 double acc = 0.0;
759 int i = 0;
760 set<double>::iterator citn = _percentiles.begin();
761 set<double>::iterator cit0 = citn++;
762 for (auto it = _flexiBins.begin(); it != _flexiBins.end();) {
763 auto curr = it++;
764 ++i;
765 double w = curr->_weightsum / _weightsum;
766 acc += w;
767 if (curr == _flexiBins.begin() || it == _flexiBins.end() || acc > *citn) {
768 if (acc > *citn) cit0 = citn++;
769 cerr << setw(6) << i << setw(12) << acc - w << setw(12) << acc << setw(8) << curr->_n << setw(8)
770 << curr->_m << setw(12) << curr->_cestLo << setw(12) << curr->_cestHi << endl;
771 }
772 }
773 cerr << "Number of sampler bins: " << _flexiBins.size() << endl;
774 }
775
779
780 public:
781
786
789
790 protected:
791
793 void project(const Event& e) {
794 _estimate = apply<HepMCHeavyIon>(e, "HI").centrality();
795 }
796
798 CmpState compare(const Projection& p) const {
799 return mkNamedPCmp(p, "GeneratedCentrality");
800 }
801 };
802
803
804}
805
806#endif
double estimator() const
Definition CentralityBinner.hh:238
void normalizePerEvent()
Definition CentralityBinner.hh:216
map< double, double > edges() const
Definition CentralityBinner.hh:222
T select(const Event &event, double weight=1.0)
Definition CentralityBinner.hh:194
const T & current() const
Return the current AnalysisObject from the latest call to select().
Definition CentralityBinner.hh:232
void add(T t, double cmin, double cmax, double cestmin=-1.0, double cestmax=-1.0)
Definition CentralityBinner.hh:176
void finalize()
Definition CentralityBinner.hh:681
set< FlexiBin > FlexiBinSet
Convenient typedefs.
Definition CentralityBinner.hh:374
void setProjection(const CentralityEstimator &p, string pname)
Definition CentralityBinner.hh:154
CentralityBinner(int maxbins=200, double wlim=0.02)
Definition CentralityBinner.hh:146
void debug()
Print out the _flexiBins to cerr.
Definition CentralityBinner.hh:756
virtual std::string name() const
Return the class name.
Definition CentralityBinner.hh:160
Base class for projections profile observable value vs the collision centrality.
Definition CentralityBinner.hh:34
void project(const Event &e)
Perform the projection on the Event.
Definition CentralityBinner.hh:50
CentralityEstimator()
Constructor.
Definition CentralityBinner.hh:38
CmpState compare(const Projection &p) const
Compare projections.
Definition CentralityBinner.hh:58
RIVET_DEFAULT_PROJ_CLONE(CentralityEstimator)
Clone on the heap.
double estimate() const
The value of the centrality estimate.
Definition CentralityBinner.hh:66
Representation of a HepMC event, and enabler of Projection caching.
Definition Event.hh:22
GeneratedCentrality()
Constructor.
Definition CentralityBinner.hh:783
CmpState compare(const Projection &p) const
Compare projections.
Definition CentralityBinner.hh:798
void project(const Event &e)
Perform the projection on the Event.
Definition CentralityBinner.hh:793
RIVET_DEFAULT_PROJ_CLONE(GeneratedCentrality)
Clone on the heap.
Definition HepMCHeavyIon.hh:12
std::enable_if_t< std::is_base_of< Projection, PROJ >::value, const PROJ & > apply(const Event &evt, const Projection &proj) const
Apply the supplied projection on event evt.
Definition ProjectionApplier.hh:124
const PROJ & declare(const PROJ &proj, const std::string &name) const
Register a contained projection (user-facing version).
Definition ProjectionApplier.hh:205
ProjectionApplier()
Constructor.
Base class for all Rivet projections.
Definition Projection.hh:29
Projection()
The default constructor.
friend class Event
Event is a friend.
Definition Projection.hh:33
void setName(const std::string &name)
Used by derived classes to set their name.
Definition Projection.hh:146
Cmp< Projection > mkNamedPCmp(const Projection &otherparent, const std::string &pname) const
STL iterator class.
#define MSG_WARNING(x)
Warning messages for non-fatal bad things, using MSG_LVL.
Definition Logging.hh:200
double p(const ParticleBase &p)
Unbound function access to p.
Definition ParticleBaseUtils.hh:819
Definition LHCbCommon.hh:9
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, signed_if_mixed_t< N1, N2 > > max(N1 a, N2 b)
Get the maximum of two numbers.
Definition MathUtils.hh:124
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, signed_if_mixed_t< N1, N2 > > min(N1 a, N2 b)
Get the minimum of two numbers.
Definition MathUtils.hh:113