-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Expand file tree
/
Copy pathGenPlusSimParticleProducer.cc
More file actions
360 lines (317 loc) · 15.6 KB
/
GenPlusSimParticleProducer.cc
File metadata and controls
360 lines (317 loc) · 15.6 KB
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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/**
\class pat::GenPlusSimParticleProducer GenPlusSimParticleProducer.h "PhysicsTools/PatAlgos/interface/GenPlusSimParticleProducer.h"
\brief Produces reco::GenParticle from SimTracks
The GenPlusSimParticleProducer produces GenParticles from SimTracks,
so they can be used for MC matching. A copy of the original genParticle list
is made and the genParticles created from the GEANT/FAMOS particles are added
to the list including all ancestors and correct mother/daughter references
Sample useage in cfg.py file:
process.genParticlePlusGEANT = cms.EDProducer("GenPlusSimParticleProducer",
src = cms.InputTag("g4SimHits"), # use "fastSimProducer" for FastSim
setStatus = cms.int32(8), # set status = 8 for GEANT GPs
particleTypes = cms.vstring("pi+"), # also picks pi- (optional)
filter = cms.vstring("pt > 0.0"), # just for testing
genParticles = cms.InputTag("genParticles") # original genParticle list
)
\author Jordan Tucker (original module), Keith Ulmer (generalization)
*/
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/stream/EDProducer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/EventSetup.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
#include "DataFormats/HepMCCandidate/interface/GenParticleFwd.h"
#include "SimDataFormats/Track/interface/SimTrackContainer.h"
#include "SimDataFormats/Vertex/interface/SimVertexContainer.h"
#include "CommonTools/Utils/interface/StringCutObjectSelector.h"
#include "SimGeneral/HepPDTRecord/interface/PdtEntry.h"
#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h"
#include <ext/algorithm>
#include <memory>
namespace pat {
class GenPlusSimParticleProducer : public edm::stream::EDProducer<> {
public:
explicit GenPlusSimParticleProducer(const edm::ParameterSet &);
private:
void produce(edm::Event &, const edm::EventSetup &) override;
bool firstEvent_;
edm::EDGetTokenT<edm::SimTrackContainer> simtracksToken_;
edm::EDGetTokenT<edm::SimVertexContainer> simverticesToken_;
int setStatus_;
std::set<int> pdgIds_; // these are the ones we really use
std::vector<PdtEntry> pdts_; // these are needed before we get the EventSetup
typedef StringCutObjectSelector<reco::GenParticle> StrFilter;
std::unique_ptr<StrFilter> filter_;
/// Collection of GenParticles I need to make refs to. It must also have its associated vector<int> of barcodes, aligned with them.
edm::EDGetTokenT<reco::GenParticleCollection> gensToken_;
edm::EDGetTokenT<std::vector<int>> genBarcodesToken_;
edm::ESGetToken<HepPDT::ParticleDataTable, edm::DefaultRecord> tableToken_;
/// Try to link the GEANT particle to the generator particle it came from
/** Arguments:
* -- Specific --
* gp: GenParticle made from the GEANT particle
* st: The GEANT simTrack for which we create a genParticle
*
* -- GEANT related --
* simtks: A list of GEANT tracks, sorted by track id
* simvtxs: The list of GEANT vertices, in their natural order (skimtks have pointers into this vector!)
*
* -- GenParticle related --
* gens : Handle to the GenParticles, to make the ref to
* genBarcodes : Barcodes for each GenParticle, in a vector aligned to the GenParticleCollection.
* barcodesAreSorted: true if the barcodes are sorted (which means I can use binary_search on them) */
void addGenParticle(const SimTrack &stMom,
const SimTrack &stDau,
unsigned int momidx,
const edm::SimTrackContainer &simtks,
const edm::SimVertexContainer &simvtxs,
reco::GenParticleCollection &mergedGens,
const reco::GenParticleRefProd ref,
std::vector<int> &genBarcodes,
bool &barcodesAreSorted) const;
struct LessById {
bool operator()(const SimTrack &tk1, const SimTrack &tk2) const { return tk1.trackId() < tk2.trackId(); }
bool operator()(const SimTrack &tk1, unsigned int id) const { return tk1.trackId() < id; }
bool operator()(unsigned int id, const SimTrack &tk2) const { return id < tk2.trackId(); }
};
};
} // namespace pat
using namespace std;
using namespace edm;
using namespace reco;
using pat::GenPlusSimParticleProducer;
GenPlusSimParticleProducer::GenPlusSimParticleProducer(const ParameterSet &cfg)
: firstEvent_(true),
simtracksToken_(consumes<SimTrackContainer>(cfg.getParameter<InputTag>("src"))), // source sim tracks & vertices
simverticesToken_(
consumes<SimVertexContainer>(cfg.getParameter<InputTag>("src"))), // source sim tracks & vertices
setStatus_(cfg.getParameter<int32_t>("setStatus")), // set status of GenParticle to this code
gensToken_(consumes<GenParticleCollection>(
cfg.getParameter<InputTag>("genParticles"))), // get the genParticles to add GEANT particles to
genBarcodesToken_(consumes<std::vector<int>>(
cfg.getParameter<InputTag>("genParticles"))) // get the genParticles to add GEANT particles to
{
// Possibly allow a list of particle types
if (cfg.exists("particleTypes")) {
pdts_ = cfg.getParameter<vector<PdtEntry>>("particleTypes");
if (!pdts_.empty()) {
tableToken_ = esConsumes();
}
}
// Possibly allow a string cut
if (cfg.existsAs<string>("filter")) {
string filter = cfg.getParameter<string>("filter");
if (!filter.empty()) {
filter_ = std::make_unique<StrFilter>(filter);
}
}
produces<GenParticleCollection>();
produces<vector<int>>();
}
void GenPlusSimParticleProducer::addGenParticle(const SimTrack &stMom,
const SimTrack &stDau,
unsigned int momidx,
const SimTrackContainer &simtracksSorted,
const SimVertexContainer &simvertices,
reco::GenParticleCollection &mergedGens,
const GenParticleRefProd ref,
std::vector<int> &genBarcodes,
bool &barcodesAreSorted) const {
// Make the genParticle for stDau and add it to the new collection and update the parent-child relationship
// Make up a GenParticleCandidate from the GEANT track info.
int charge = static_cast<int>(stDau.charge());
const Particle::LorentzVector &p4 = stDau.momentum();
Particle::Point vtx; // = (0,0,0) by default
if (!stDau.noVertex())
vtx = simvertices[stDau.vertIndex()].position();
GenParticle genp(charge, p4, vtx, stDau.type(), setStatus_, true);
// Maybe apply filter on the particle
if (filter_.get() != nullptr) {
if (!(*filter_)(genp))
return;
}
reco::GenParticleRef parentRef(ref, momidx);
genp.addMother(parentRef);
mergedGens.push_back(genp);
// get the index for the daughter just added
unsigned int dauidx = mergedGens.size() - 1;
// update add daughter relationship
reco::GenParticle &cand = mergedGens[momidx];
cand.addDaughter(GenParticleRef(ref, dauidx));
//look for simtrack daughters of stDau to see if we need to recur further down the chain
for (SimTrackContainer::const_iterator isimtrk = simtracksSorted.begin(); isimtrk != simtracksSorted.end();
++isimtrk) {
if (!isimtrk->noVertex()) {
// Pick the vertex (isimtrk.vertIndex() is really an index)
const SimVertex &vtx = simvertices[isimtrk->vertIndex()];
// Check if the vertex has a parent track (otherwise, we're lost)
if (!vtx.noParent()) {
// Now note that vtx.parentIndex() is NOT an index, it's a track id, so I have to search for it
unsigned int idx = vtx.parentIndex();
SimTrackContainer::const_iterator it =
std::lower_bound(simtracksSorted.begin(), simtracksSorted.end(), idx, LessById());
if ((it != simtracksSorted.end()) && (it->trackId() == idx)) {
if (it->trackId() == stDau.trackId()) {
//need the genparticle index of stDau which is dauidx
addGenParticle(
stDau, *isimtrk, dauidx, simtracksSorted, simvertices, mergedGens, ref, genBarcodes, barcodesAreSorted);
}
}
}
}
}
}
void GenPlusSimParticleProducer::produce(Event &event, const EventSetup &iSetup) {
if (firstEvent_) {
if (!pdts_.empty()) {
auto const &pdt = iSetup.getData(tableToken_);
pdgIds_.clear();
for (vector<PdtEntry>::iterator itp = pdts_.begin(), edp = pdts_.end(); itp != edp; ++itp) {
itp->setup(pdt); // decode string->pdgId and vice-versa
pdgIds_.insert(std::abs(itp->pdgId()));
}
pdts_.clear();
}
firstEvent_ = false;
}
// Simulated tracks (i.e. GEANT particles).
Handle<SimTrackContainer> simtracks;
event.getByToken(simtracksToken_, simtracks);
// Need to check that SimTrackContainer is sorted; otherwise, copy and sort :-(
std::unique_ptr<SimTrackContainer> simtracksTmp;
const SimTrackContainer *simtracksSorted = &*simtracks;
if (!__gnu_cxx::is_sorted(simtracks->begin(), simtracks->end(), LessById())) {
simtracksTmp = std::make_unique<SimTrackContainer>(*simtracks);
std::sort(simtracksTmp->begin(), simtracksTmp->end(), LessById());
simtracksSorted = &*simtracksTmp;
}
// Get the associated vertices
Handle<SimVertexContainer> simvertices;
event.getByToken(simverticesToken_, simvertices);
// Get the GenParticles and barcodes, if needed to set mother and daughter links
Handle<GenParticleCollection> gens;
Handle<std::vector<int>> genBarcodes;
bool barcodesAreSorted = true;
event.getByToken(gensToken_, gens);
event.getByToken(genBarcodesToken_, genBarcodes);
if (gens->size() != genBarcodes->size())
throw cms::Exception("Corrupt data") << "Barcodes not of the same size as GenParticles!\n";
// make the output collection
auto candsPtr = std::make_unique<GenParticleCollection>();
GenParticleCollection &cands = *candsPtr;
const GenParticleRefProd ref = event.getRefBeforePut<GenParticleCollection>();
// add the original genParticles to the merged output list
for (size_t i = 0; i < gens->size(); ++i) {
reco::GenParticle cand((*gens)[i]);
cands.push_back(cand);
}
// make new barcodes vector and fill it with the original list
auto newGenBarcodes = std::make_unique<vector<int>>();
for (unsigned int i = 0; i < genBarcodes->size(); ++i) {
newGenBarcodes->push_back((*genBarcodes)[i]);
}
barcodesAreSorted = __gnu_cxx::is_sorted(newGenBarcodes->begin(), newGenBarcodes->end());
for (size_t i = 0; i < cands.size(); ++i) {
reco::GenParticle &cand = cands[i];
size_t nDaus = cand.numberOfDaughters();
GenParticleRefVector daus = cand.daughterRefVector();
cand.resetDaughters(ref.id());
for (size_t d = 0; d < nDaus; ++d) {
cand.addDaughter(GenParticleRef(ref, daus[d].key()));
}
size_t nMoms = cand.numberOfMothers();
GenParticleRefVector moms = cand.motherRefVector();
cand.resetMothers(ref.id());
for (size_t m = 0; m < nMoms; ++m) {
cand.addMother(GenParticleRef(ref, moms[m].key()));
}
}
for (SimTrackContainer::const_iterator isimtrk = simtracks->begin(); isimtrk != simtracks->end(); ++isimtrk) {
// Special case for when simTracks need to be added to pythia track filtered by particleType, e.g. a particle with ctau=0.1mm
if (isimtrk->genpartIndex() != -1 && !pdgIds_.empty() &&
(pdgIds_.find(std::abs(isimtrk->type())) != pdgIds_.end())) {
std::vector<int>::const_iterator itIndex;
if (barcodesAreSorted) {
itIndex = std::lower_bound(genBarcodes->begin(), genBarcodes->end(), isimtrk->genpartIndex());
} else {
itIndex = std::find(genBarcodes->begin(), genBarcodes->end(), isimtrk->genpartIndex());
}
if ((itIndex != genBarcodes->end()) && (*itIndex == isimtrk->genpartIndex())) {
const unsigned int momidx = itIndex - genBarcodes->begin();
for (SimTrackContainer::const_iterator idau = simtracksSorted->begin(); idau != simtracksSorted->end();
++idau) {
if (idau->noVertex())
continue;
const SimVertex &dvtx = (*simvertices)[idau->vertIndex()];
if (dvtx.noParent())
continue;
if (dvtx.parentIndex() == static_cast<int>(isimtrk->trackId())) {
addGenParticle(*isimtrk,
*idau,
momidx,
*simtracksSorted,
*simvertices,
*candsPtr,
ref,
*newGenBarcodes,
barcodesAreSorted);
}
}
}
}
else {
// Skip PYTHIA tracks.
if (isimtrk->genpartIndex() != -1)
continue;
// Maybe apply the PdgId filter
if (!pdgIds_.empty()) { // if we have a filter on pdg ids
if (pdgIds_.find(std::abs(isimtrk->type())) == pdgIds_.end())
continue;
}
// find simtrack that has a genParticle match to its parent
// Look at the production vertex. If there is no vertex, I can do nothing...
if (!isimtrk->noVertex()) {
// Pick the vertex (isimtrk.vertIndex() is really an index)
const SimVertex &vtx = (*simvertices)[isimtrk->vertIndex()];
// Check if the vertex has a parent track (otherwise, we're lost)
if (!vtx.noParent()) {
// Now note that vtx.parentIndex() is NOT an index, it's a track id, so I have to search for it
unsigned int idx = vtx.parentIndex();
SimTrackContainer::const_iterator it =
std::lower_bound(simtracksSorted->begin(), simtracksSorted->end(), idx, LessById());
if ((it != simtracksSorted->end()) && (it->trackId() == idx)) { //it is the parent sim track
if (it->genpartIndex() != -1) {
std::vector<int>::const_iterator itIndex;
if (barcodesAreSorted) {
itIndex = std::lower_bound(genBarcodes->begin(), genBarcodes->end(), it->genpartIndex());
} else {
itIndex = std::find(genBarcodes->begin(), genBarcodes->end(), it->genpartIndex());
}
// Check that I found something
// I need to check '*itIndex == it->genpartIndex()' because lower_bound just finds the right spot for an item in a sorted list, not the item
if ((itIndex != genBarcodes->end()) && (*itIndex == it->genpartIndex())) {
// Ok, I'll make the genParticle for st and add it to the new collection updating the map and parent-child relationship
// pass the mother and daughter sim tracks and the mother genParticle to method to create the daughter genParticle and recur
unsigned int momidx = itIndex - genBarcodes->begin();
addGenParticle(*it,
*isimtrk,
momidx,
*simtracksSorted,
*simvertices,
*candsPtr,
ref,
*newGenBarcodes,
barcodesAreSorted);
}
}
}
}
}
}
}
event.put(std::move(candsPtr));
event.put(std::move(newGenBarcodes));
}
DEFINE_FWK_MODULE(GenPlusSimParticleProducer);