File indexing completed on 2025-05-12 09:05:02
0001
0002 #ifndef RIVET_EventMixingFinalState_HH
0003 #define RIVET_EventMixingFinalState_HH
0004
0005 #include "Rivet/Projection.hh"
0006 #include "Rivet/Projections/ParticleFinder.hh"
0007 #include "Rivet/Tools/Random.hh"
0008 #include <deque>
0009 #include <algorithm>
0010
0011 namespace Rivet {
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 template <class RandomAccessIterator,
0039 class WeightIterator, class RandomNumberGenerator>
0040 void weighted_shuffle(RandomAccessIterator first, RandomAccessIterator last,
0041 WeightIterator fw, WeightIterator lw, RandomNumberGenerator& g) {
0042 while(first != last && fw != lw) {
0043 std::discrete_distribution<int> weightDist(fw, lw);
0044 int i = weightDist(g);
0045 if(i){
0046 std::iter_swap(first, next(first, i));
0047 std::iter_swap(fw, next(fw, i));
0048 }
0049 ++first;
0050 ++fw;
0051 }
0052 }
0053
0054
0055 typedef pair<Particles, double> MixEvent;
0056 typedef map<double, std::deque<MixEvent> > MixMap;
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 class EventMixingBase : public Projection {
0072 protected:
0073
0074 EventMixingBase(const Projection & mixObsProj, const ParticleFinder& mix,
0075 size_t nMixIn, double oMin, double oMax, double deltao,
0076 const size_t defaultIdx) : nMix(nMixIn), unitWeights(true) {
0077
0078
0079 setName("EventMixingBase");
0080 declare(mixObsProj,"OBS");
0081 declare(mix,"MIX");
0082 MSG_WARNING("EventMixing is not fully validated. Use with caution.");
0083
0084 _defaultWeightIdx = defaultIdx;
0085
0086 for(double o = oMin; o < oMax; o+=deltao )
0087 mixEvents[o] = std::deque<MixEvent>();
0088 }
0089
0090
0091 using Projection::operator =;
0092
0093
0094 public:
0095
0096
0097
0098 bool hasMixingEvents() const {
0099 MixMap::const_iterator mixItr = mixEvents.lower_bound(mObs);
0100 if(mixItr == mixEvents.end() || mixItr->second.size() < nMix + 1)
0101 return false;
0102 return true;
0103 }
0104
0105
0106 vector<MixEvent> getMixingEvents() const {
0107 if (!hasMixingEvents())
0108 return vector<MixEvent>();
0109 MixMap::const_iterator mixItr = mixEvents.lower_bound(mObs);
0110 return vector<MixEvent>(mixItr->second.begin(), mixItr->second.end() - 1);
0111 }
0112
0113
0114
0115
0116
0117 virtual const Particles particles() const {
0118
0119 if (!hasMixingEvents())
0120 return Particles();
0121
0122 MixMap::const_iterator mixItr = mixEvents.lower_bound(mObs);
0123 vector<MixEvent> mixEvents(mixItr->second.begin(), mixItr->second.end() - 1);
0124
0125 Particles mixParticles;
0126 vector<double> weights;
0127 size_t pSize = 0;
0128 for (size_t i = 0; i < mixEvents.size(); ++i)
0129 pSize+=mixEvents[i].first.size();
0130 mixParticles.reserve(pSize);
0131 weights.reserve(pSize);
0132
0133 for (size_t i = 0; i < mixEvents.size(); ++i) {
0134 mixParticles.insert(mixParticles.end(), mixEvents[i].first.begin(), mixEvents[i].first.end());
0135 vector<double> tmp(mixEvents[i].first.size(), mixEvents[i].second);
0136 weights.insert(weights.end(), tmp.begin(), tmp.end());
0137 }
0138
0139
0140 if (unitWeights) {
0141
0142
0143 std::shuffle(mixParticles.begin(), mixParticles.end(), rng());
0144 return mixParticles;
0145 } else {
0146 weighted_shuffle(mixParticles.begin(), mixParticles.end(), weights.begin(), weights.end(), rng());
0147 Particles tmp = vector<Particle>(mixParticles.begin(), mixParticles.begin() + size_t(ceil(mixParticles.size() / 2)));
0148 return tmp;
0149 }
0150 }
0151
0152
0153 protected:
0154
0155
0156
0157
0158 virtual void calculateMixingObs(const Projection* mProj) = 0;
0159
0160
0161
0162 void project(const Event& e) {
0163 const Projection* mixObsProjPtr = &apply<Projection>(e, "OBS");
0164 calculateMixingObs(mixObsProjPtr);
0165 MixMap::iterator mixItr = mixEvents.lower_bound(mObs);
0166 if (mixItr == mixEvents.end()){
0167
0168 MSG_DEBUG("Mixing observable out of bounds.");
0169 return;
0170 }
0171 const Particles mix = apply<ParticleFinder>(e, "MIX").particles();
0172 mixItr->second.push_back(make_pair(mix,e.weights()[_defaultWeightIdx]));
0173
0174 if (unitWeights && e.weights()[_defaultWeightIdx] != 1.0 ) {
0175 unitWeights = false;
0176 nMix *= 2;
0177 }
0178 if (mixItr->second.size() > nMix + 1)
0179 mixItr->second.pop_front();
0180 }
0181
0182
0183
0184 CmpState compare(const Projection& p) const {
0185 return mkNamedPCmp(p,"OBS");
0186 }
0187
0188
0189
0190 double mObs;
0191
0192
0193 protected:
0194
0195
0196 size_t nMix;
0197
0198
0199 MixMap mixEvents;
0200
0201
0202 bool unitWeights;
0203
0204 size_t _defaultWeightIdx;
0205
0206 };
0207
0208
0209
0210 class EventMixingFinalState : public EventMixingBase {
0211 public:
0212 EventMixingFinalState(const ParticleFinder & mixObsProj,
0213 const ParticleFinder& mix, size_t nMixIn, double oMin, double oMax,
0214 double deltao, const size_t defaultIdx) :
0215 EventMixingBase(mixObsProj, mix, nMixIn, oMin, oMax, deltao, defaultIdx) {
0216 setName("EventMixingFinalState");
0217 }
0218
0219 RIVET_DEFAULT_PROJ_CLONE(EventMixingFinalState);
0220
0221
0222 using Projection::operator =;
0223
0224
0225 protected:
0226
0227
0228 virtual void calculateMixingObs(const Projection* mProj) {
0229 mObs = ((ParticleFinder*) mProj)->particles().size();
0230 }
0231
0232 };
0233
0234
0235
0236 class EventMixingCentrality : public EventMixingBase {
0237 public:
0238
0239 EventMixingCentrality(const CentralityProjection& mixObsProj,
0240 const ParticleFinder& mix, size_t nMixIn, double oMin, double oMax,
0241 double deltao, const size_t defaultIdx) :
0242 EventMixingBase(mixObsProj, mix, nMixIn, oMin, oMax, deltao, defaultIdx) {
0243 setName("EventMixingCentrality");
0244 }
0245
0246 RIVET_DEFAULT_PROJ_CLONE(EventMixingCentrality);
0247
0248
0249 using Projection::operator =;
0250
0251 protected:
0252
0253
0254 virtual void calculateMixingObs(const Projection* mProj) {
0255 mObs = ((CentralityProjection*) mProj)->operator()();
0256 }
0257
0258 };
0259
0260
0261 }
0262
0263 #endif