forked from cms-sw/cmssw
/
InputGenJetsParticleSelector.cc
293 lines (251 loc) · 11 KB
/
InputGenJetsParticleSelector.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* \class GenJetInputParticleSelector
*
* Selects particles that are used as input for the GenJet collection.
* Logic: select all stable particles, except for particles specified in
* the config file that come from
* W,Z and H decays, and except for a special list, which can be used for
* unvisible BSM-particles.
* It is also possible to only selected the partonic final state,
* which means all particles before the hadronization step.
*
* The algorithm is based on code of Christophe Saout.
*
* Usage: [example for no resonance from nu an mu, and deselect invisible BSM
* particles ]
*
* module genJetParticles = InputGenJetsParticleSelector {
* InputTag src = "genParticles"
* bool partonicFinalState = false
* bool excludeResonances = true
* vuint32 excludeFromResonancePids = {13,12,14,16}
* bool tausAsJets = false
* vuint32 ignoreParticleIDs = { 1000022, 2000012, 2000014,
* 2000016, 1000039, 5000039,
* 4000012, 9900012, 9900014,
* 9900016, 39}
* }
*
*
* \author: Christophe Saout, Andreas Oehler
*
* Modifications:
*
* 04.08.2014: Dinko Ferencek
* Added support for Pythia8 (status=22 for intermediate resonances)
* 23.09.2014: Dinko Ferencek
* Generalized code to work with miniAOD (except for the partonicFinalState which requires AOD)
*
*/
#include "InputGenJetsParticleSelector.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
//#include <iostream>
#include <memory>
#include "CommonTools/CandUtils/interface/pdgIdUtils.h"
using namespace std;
InputGenJetsParticleSelector::InputGenJetsParticleSelector(const edm::ParameterSet ¶ms)
: inTag(params.getParameter<edm::InputTag>("src")),
prunedInTag(params.exists("prunedGenParticles") ? params.getParameter<edm::InputTag>("prunedGenParticles")
: edm::InputTag("prunedGenParticles")),
partonicFinalState(params.getParameter<bool>("partonicFinalState")),
excludeResonances(params.getParameter<bool>("excludeResonances")),
tausAsJets(params.getParameter<bool>("tausAsJets")),
ptMin(0.0) {
if (params.exists("ignoreParticleIDs"))
setIgnoredParticles(params.getParameter<std::vector<unsigned int> >("ignoreParticleIDs"));
setExcludeFromResonancePids(params.getParameter<std::vector<unsigned int> >("excludeFromResonancePids"));
isMiniAOD =
(params.exists("isMiniAOD") ? params.getParameter<bool>("isMiniAOD") : (inTag.label() == "packedGenParticles"));
if (isMiniAOD && partonicFinalState) {
edm::LogError("PartonicFinalStateFromMiniAOD")
<< "Partonic final state not supported for MiniAOD. Falling back to the stable particle selection.";
partonicFinalState = false;
}
produces<reco::CandidatePtrVector>();
input_genpartcoll_token_ = consumes<reco::CandidateView>(inTag);
if (isMiniAOD)
input_prunedgenpartcoll_token_ = consumes<reco::CandidateView>(prunedInTag);
}
InputGenJetsParticleSelector::~InputGenJetsParticleSelector() {}
void InputGenJetsParticleSelector::setIgnoredParticles(const std::vector<unsigned int> &particleIDs) {
ignoreParticleIDs = particleIDs;
std::sort(ignoreParticleIDs.begin(), ignoreParticleIDs.end());
}
void InputGenJetsParticleSelector::setExcludeFromResonancePids(const std::vector<unsigned int> &particleIDs) {
excludeFromResonancePids = particleIDs;
std::sort(excludeFromResonancePids.begin(), excludeFromResonancePids.end());
}
bool InputGenJetsParticleSelector::isParton(int pdgId) const {
pdgId = (pdgId > 0 ? pdgId : -pdgId) % 10000;
return (pdgId > 0 && pdgId < 6) || pdgId == 9 || (tausAsJets && pdgId == 15) || pdgId == 21;
// tops are not considered "regular" partons
// but taus eventually are (since they may hadronize later)
}
bool InputGenJetsParticleSelector::isHadron(int pdgId) {
pdgId = (pdgId > 0 ? pdgId : -pdgId) % 10000;
return (pdgId > 100 && pdgId < 900) || (pdgId > 1000 && pdgId < 9000);
}
bool InputGenJetsParticleSelector::isResonance(int pdgId) {
// gauge bosons and tops
pdgId = (pdgId > 0 ? pdgId : -pdgId) % 10000;
return (pdgId > 21 && pdgId <= 42) || pdgId == 6 || pdgId == 7 || pdgId == 8; //BUG! was 21. 22=gamma..
}
bool InputGenJetsParticleSelector::isIgnored(int pdgId) const {
pdgId = pdgId > 0 ? pdgId : -pdgId;
std::vector<unsigned int>::const_iterator pos =
std::lower_bound(ignoreParticleIDs.begin(), ignoreParticleIDs.end(), (unsigned int)pdgId);
return pos != ignoreParticleIDs.end() && *pos == (unsigned int)pdgId;
}
bool InputGenJetsParticleSelector::isExcludedFromResonance(int pdgId) const {
pdgId = pdgId > 0 ? pdgId : -pdgId;
std::vector<unsigned int>::const_iterator pos =
std::lower_bound(excludeFromResonancePids.begin(), excludeFromResonancePids.end(), (unsigned int)pdgId);
return pos != excludeFromResonancePids.end() && *pos == (unsigned int)pdgId;
}
static unsigned int partIdx(const InputGenJetsParticleSelector::ParticleVector &p, const reco::Candidate *particle) {
InputGenJetsParticleSelector::ParticleVector::const_iterator pos = std::lower_bound(p.begin(), p.end(), particle);
if (pos == p.end() || *pos != particle)
throw cms::Exception("CorruptedData") << "reco::GenEvent corrupted: Unlisted particles"
" in decay tree."
<< std::endl;
return pos - p.begin();
}
static void invalidateTree(InputGenJetsParticleSelector::ParticleBitmap &invalid,
const InputGenJetsParticleSelector::ParticleVector &p,
const reco::Candidate *particle) {
unsigned int npart = particle->numberOfDaughters();
if (!npart)
return;
for (unsigned int i = 0; i < npart; ++i) {
unsigned int idx = partIdx(p, particle->daughter(i));
if (invalid[idx])
continue;
invalid[idx] = true;
//cout<<"Invalidated: ["<<setw(4)<<idx<<"] With pt:"<<particle->daughter(i)->pt()<<endl;
invalidateTree(invalid, p, particle->daughter(i));
}
}
int InputGenJetsParticleSelector::testPartonChildren(InputGenJetsParticleSelector::ParticleBitmap &invalid,
const InputGenJetsParticleSelector::ParticleVector &p,
const reco::Candidate *particle) const {
unsigned int npart = particle->numberOfDaughters();
if (!npart) {
return 0;
}
for (unsigned int i = 0; i < npart; ++i) {
unsigned int idx = partIdx(p, particle->daughter(i));
if (invalid[idx])
continue;
if (isParton((particle->daughter(i)->pdgId()))) {
return 1;
}
if (isHadron((particle->daughter(i)->pdgId()))) {
return -1;
}
int result = testPartonChildren(invalid, p, particle->daughter(i));
if (result)
return result;
}
return 0;
}
InputGenJetsParticleSelector::ResonanceState InputGenJetsParticleSelector::fromResonance(
ParticleBitmap &invalid, const ParticleVector &p, const reco::Candidate *particle) const {
unsigned int idx = partIdx(p, particle);
int id = particle->pdgId();
if (invalid[idx])
return kIndirect;
if (isResonance(id) && (particle->status() == 3 || particle->status() == 22)) {
return kDirect;
}
if (!isIgnored(id) && (isParton(id)))
return kNo;
unsigned int nMo = particle->numberOfMothers();
if (!nMo)
return kNo;
for (unsigned int i = 0; i < nMo; ++i) {
ResonanceState result = fromResonance(invalid, p, particle->mother(i));
switch (result) {
case kNo:
break;
case kDirect:
if (particle->mother(i)->pdgId() == id || isResonance(id))
return kDirect;
if (!isExcludedFromResonance(id))
break;
[[fallthrough]];
case kIndirect:
return kIndirect;
}
}
return kNo;
}
bool InputGenJetsParticleSelector::hasPartonChildren(ParticleBitmap &invalid,
const ParticleVector &p,
const reco::Candidate *particle) const {
return testPartonChildren(invalid, p, particle) > 0;
}
//######################################################
//function NEEDED and called per EVENT by FRAMEWORK:
void InputGenJetsParticleSelector::produce(edm::StreamID, edm::Event &evt, const edm::EventSetup &evtSetup) const {
auto selected_ = std::make_unique<reco::CandidatePtrVector>();
ParticleVector particles;
edm::Handle<reco::CandidateView> prunedGenParticles;
if (isMiniAOD) {
evt.getByToken(input_prunedgenpartcoll_token_, prunedGenParticles);
for (edm::View<reco::Candidate>::const_iterator iter = prunedGenParticles->begin();
iter != prunedGenParticles->end();
++iter) {
if (iter->status() !=
1) // to avoid double-counting, skipping stable particles already contained in the collection of PackedGenParticles
particles.push_back(&*iter);
}
}
edm::Handle<reco::CandidateView> genParticles;
evt.getByToken(input_genpartcoll_token_, genParticles);
std::map<const reco::Candidate *, size_t> particlePtrIdxMap;
for (edm::View<reco::Candidate>::const_iterator iter = genParticles->begin(); iter != genParticles->end(); ++iter) {
particles.push_back(&*iter);
particlePtrIdxMap[&*iter] = (iter - genParticles->begin());
}
std::sort(particles.begin(), particles.end());
unsigned int size = particles.size();
ParticleBitmap selected(size, false);
ParticleBitmap invalid(size, false);
for (unsigned int i = 0; i < size; i++) {
const reco::Candidate *particle = particles[i];
if (invalid[i])
continue;
if (particle->status() == 1) // selecting stable particles
selected[i] = true;
if (partonicFinalState && isParton(particle->pdgId())) {
if (particle->numberOfDaughters() == 0 && particle->status() != 1) {
// some brokenness in event...
invalid[i] = true;
} else if (!hasPartonChildren(invalid, particles, particle)) {
selected[i] = true;
invalidateTree(invalid, particles, particle); //this?!?
}
}
}
for (size_t idx = 0; idx < size; ++idx) {
const reco::Candidate *particle = particles[idx];
if (!selected[idx] || invalid[idx]) {
continue;
}
if (excludeResonances && fromResonance(invalid, particles, particle)) {
invalid[idx] = true;
//cout<<"[INPUTSELECTOR] Invalidates FROM RESONANCE!: ["<<setw(4)<<idx<<"] "<<particle->pdgId()<<" "<<particle->pt()<<endl;
continue;
}
if (isIgnored(particle->pdgId())) {
continue;
}
if (particle->pt() >= ptMin) {
selected_->push_back(genParticles->ptrAt(particlePtrIdxMap[particle]));
//cout<<"Finally we have: ["<<setw(4)<<idx<<"] "<<setw(4)<<particle->pdgId()<<" "<<particle->pt()<<endl;
}
}
evt.put(std::move(selected_));
}
//define this as a plug-in
DEFINE_FWK_MODULE(InputGenJetsParticleSelector);