1+ #include " GeneratorInterface/GenFilters/plugins/PhotonGenFilter.h"
2+ #include " SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
3+ #include < iostream>
4+
5+ using namespace edm ;
6+ using namespace std ;
7+
8+ PhotonGenFilter::PhotonGenFilter (const edm::ParameterSet &iConfig)
9+ : token_(consumes<edm::HepMCProduct>(
10+ edm::InputTag (iConfig.getUntrackedParameter(" moduleLabel" , std::string(" generator" )), "unsmeared"))) {
11+ // Constructor implementation
12+ ptMin = iConfig.getUntrackedParameter <double >(" MinPt" , 20 .);
13+ etaMin = iConfig.getUntrackedParameter <double >(" MinEta" , -2.4 );
14+ etaMax = iConfig.getUntrackedParameter <double >(" MaxEta" , 2.4 );
15+ drMin = iConfig.getUntrackedParameter <double >(" drMin" , 0.1 );
16+ ptThreshold = iConfig.getUntrackedParameter <double >(" ptThreshold" , 2 .);
17+ }
18+
19+ PhotonGenFilter::~PhotonGenFilter () {
20+ // Destructor implementation
21+ }
22+
23+ bool PhotonGenFilter::filter (edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const {
24+ using namespace edm ;
25+ Handle<HepMCProduct> evt;
26+ iEvent.getByToken (token_, evt);
27+ const HepMC::GenEvent *myGenEvent = evt->GetEvent ();
28+ bool accepted_event = false ;
29+
30+ for (HepMC::GenEvent::particle_const_iterator p = myGenEvent->particles_begin (); p != myGenEvent->particles_end ();
31+ ++p) { // loop through all particles
32+ if ((*p)->pdg_id () == 22 && !hasAncestor (*p, [](int x) {
33+ return x > 30 && x != 2212 ;
34+ })) { // loop through all photons that don't come from hadrons
35+ if ((*p)->momentum ().perp () > ptMin && (*p)->status () == 1 && (*p)->momentum ().eta () > etaMin &&
36+ (*p)->momentum ().eta () < etaMax) { // check if photon passes pt and eta cuts
37+ bool good_photon = true ;
38+ double phi = (*p)->momentum ().phi ();
39+ double eta = (*p)->momentum ().eta ();
40+ double pt = (*p)->momentum ().perp ();
41+ double frixione_isolation_coefficient = pt / (1 - cos (drMin));
42+ vector<double > particles_pt, particles_deltar;
43+ for (HepMC::GenEvent::particle_const_iterator q = myGenEvent->particles_begin ();
44+ q != myGenEvent->particles_end ();
45+ ++q) { // loop through all particles to compute frixione isolation
46+ if (&p != &q) { // don't compare the photon to itself
47+ if ((*q)->momentum ().perp () > ptThreshold && (*q)->pdg_id () != 22 && (*q)->pdg_id () != 12 &&
48+ (*q)->pdg_id () != 14 && (*q)->pdg_id () != 16 &&
49+ (*q)->status () == 1 ) { // check if particle passes pt and status cuts and is not a neutrino or photon
50+ double phi2 = (*q)->momentum ().phi ();
51+ double deltaphi = fabs (phi - phi2);
52+ if (deltaphi > M_PI)
53+ deltaphi = 2 . * M_PI - deltaphi;
54+ double eta2 = (*q)->momentum ().eta ();
55+ double deltaeta = fabs (eta - eta2);
56+ double deltaR = sqrt (deltaeta * deltaeta + deltaphi * deltaphi);
57+ if (deltaR < drMin) // check if particle is within drMin of photon, for isolation
58+ {
59+ particles_pt.push_back ((*q)->momentum ().perp ());
60+ particles_deltar.push_back (deltaR);
61+ }
62+ }
63+ }
64+ }
65+ // order particles_pt and particles_deltar according to increasing particles_deltar
66+ for (unsigned int i = 0 ; i < particles_deltar.size (); i++) {
67+ for (unsigned int j = i + 1 ; j < particles_deltar.size (); j++) {
68+ if (particles_deltar[i] > particles_deltar[j]) {
69+ double temp = particles_deltar[i];
70+ particles_deltar[i] = particles_deltar[j];
71+ particles_deltar[j] = temp;
72+ temp = particles_pt[i];
73+ particles_pt[i] = particles_pt[j];
74+ particles_pt[j] = temp;
75+ }
76+ }
77+ }
78+ // calculate frixione isolation
79+ double total_pt = 0 ;
80+ for (unsigned int i = 0 ; i < particles_deltar.size (); i++) {
81+ total_pt += particles_pt[i];
82+ if (total_pt > frixione_isolation_coefficient * (1 - cos (particles_deltar[i]))) {
83+ good_photon =
84+ false ; // if for some delta R the isolation condition is not satisfied, the photon is not good
85+ break ;
86+ }
87+ }
88+ if (good_photon) {
89+ if (hasAncestor (*p, [](int x) { return x == 11 || x == 13 || x == 15 ; }) ||
90+ hasAncestor (
91+ *p,
92+ [](int x) { return x == 24 || x == 5 ; },
93+ true ,
94+ false )) { // check if photon is from decay and defines the event as acceptable
95+ accepted_event = true ;
96+ }
97+ if (!hasAncestor (*p, [](int x) { return x == 11 || x == 13 || x == 15 ; }) &&
98+ hasAncestor (
99+ *p,
100+ [](int x) { return x == 24 || x == 5 ; },
101+ false ,
102+ true )) { // check if photon comes from the hard process and discards it, in case it is
103+ return false ;
104+ }
105+ }
106+ }
107+ }
108+ }
109+
110+ // Implementation for event filtering
111+ return accepted_event; // Accept if it has found at least one good photon from decay and none from hard process
112+ }
113+
114+ void PhotonGenFilter::fillDescriptions (edm::ConfigurationDescriptions &descriptions) {
115+ edm::ParameterSetDescription desc;
116+ desc.addUntracked <double >(" MaxEta" , 2.4 );
117+ desc.addUntracked <double >(" MinEta" , -2.4 );
118+ desc.addUntracked <double >(" MinPt" , 20 .);
119+ desc.addUntracked <double >(" drMin" , 0.1 );
120+ desc.addUntracked <double >(" ptThreshold" , 2 .);
121+
122+ descriptions.add (" PhotonGenFilter" , desc);
123+ }
124+
125+ bool PhotonGenFilter::hasAncestor (
126+ HepMC::GenParticle *particle,
127+ function<bool (int )> check,
128+ bool isWorBFromDecayCheck,
129+ bool isWorBPromptCheck) const { // function to check if a particle has a certain ancestor
130+ if (!particle)
131+ return false ;
132+
133+ HepMC::GenVertex *prodVertex = particle->production_vertex ();
134+
135+ // If the particle doesn't have a production vertex, it has no parents.
136+ if (!prodVertex)
137+ return false ;
138+
139+ // Loop over all parents (incoming particles) of the vertex
140+ for (auto parent = prodVertex->particles_begin (HepMC::parents); parent != prodVertex->particles_end (HepMC::parents);
141+ ++parent) {
142+ int pdgId = abs ((*parent)->pdg_id ());
143+
144+ // Check if the PDG ID respects a check
145+ if (check (pdgId)) {
146+ if (isWorBFromDecayCheck) {
147+ return hasAncestor (
148+ *parent,
149+ [](int x) { return x == 6 ; },
150+ false ,
151+ false ); // if the photon has a W or b quark ancestor, check if it comes from a top quark
152+ } else if (isWorBPromptCheck) {
153+ return !hasAncestor (
154+ *parent,
155+ [](int x) { return x == 6 ; },
156+ false ,
157+ false ); // if the photon has a W or b quark ancestor, check that it doesn't come from a top quark decay (therefore it comes form the hard process)
158+ } else
159+ return true ;
160+ }
161+
162+ return hasAncestor (
163+ *parent, check, isWorBFromDecayCheck, isWorBPromptCheck); // Recursively check the ancestry of the parent
164+ }
165+
166+ return false ;
167+ }
168+
169+ DEFINE_FWK_MODULE (PhotonGenFilter);
0 commit comments