Skip to content

Commit 71f41a6

Browse files
authored
Merge pull request #47310 from MohitS704/backport_filter_2022
Backporting MC Filter to CMSSW_12_4_X series for Run3 2022 production
2 parents 9e6cb6c + 8d3b216 commit 71f41a6

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#include "GeneratorInterface/GenFilters/plugins/MCFilterZboostHelper.h"
2+
#include "DataFormats/Common/interface/Handle.h"
3+
#include "FWCore/Framework/interface/global/EDFilter.h"
4+
#include "FWCore/Framework/interface/Event.h"
5+
#include "FWCore/Framework/interface/Frameworkfwd.h"
6+
#include "FWCore/Framework/interface/MakerMacros.h"
7+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
8+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
9+
#include "FWCore/Utilities/interface/EDGetToken.h"
10+
#include "FWCore/Utilities/interface/InputTag.h"
11+
#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
12+
13+
#include <vector>
14+
#include <iostream>
15+
#include <unordered_map>
16+
#include <tuple>
17+
18+
class MCMultiParticleMassFilter : public edm::global::EDFilter<> {
19+
public:
20+
explicit MCMultiParticleMassFilter(const edm::ParameterSet&);
21+
~MCMultiParticleMassFilter() override;
22+
23+
private:
24+
bool filter(edm::StreamID, edm::Event& iEvent, const edm::EventSetup&) const override;
25+
bool recurseLoop(std::vector<HepMC::GenParticle*>& particlesThatPassCuts, std::vector<int> indices, int depth) const;
26+
27+
/* Member data */
28+
const edm::EDGetTokenT<edm::HepMCProduct> token_;
29+
const std::vector<int> particleID;
30+
std::vector<double> ptMin;
31+
std::vector<double> etaMax;
32+
std::vector<int> status;
33+
34+
//Maps each particle ID provided to its required pt, max eta, and status
35+
std::unordered_map<int, std::tuple<double, double, int>> cutPerParticle;
36+
37+
const double minTotalMass;
38+
const double maxTotalMass;
39+
40+
double minTotalMassSq;
41+
double maxTotalMassSq;
42+
int nParticles;
43+
44+
int particleSumTo;
45+
int particleProdTo;
46+
};
47+
48+
using namespace edm;
49+
using namespace std;
50+
51+
MCMultiParticleMassFilter::MCMultiParticleMassFilter(const edm::ParameterSet& iConfig)
52+
: token_(consumes<edm::HepMCProduct>(
53+
iConfig.getUntrackedParameter<edm::InputTag>("src", edm::InputTag("generator", "unsmeared")))),
54+
particleID(iConfig.getParameter<std::vector<int>>("ParticleID")),
55+
ptMin(iConfig.getParameter<std::vector<double>>("PtMin")),
56+
etaMax(iConfig.getParameter<std::vector<double>>("EtaMax")),
57+
status(iConfig.getParameter<std::vector<int>>("Status")),
58+
minTotalMass(iConfig.getParameter<double>("minTotalMass")),
59+
maxTotalMass(iConfig.getParameter<double>("maxTotalMass")) {
60+
nParticles = particleID.size();
61+
minTotalMassSq = minTotalMass * minTotalMass;
62+
maxTotalMassSq = maxTotalMass * maxTotalMass;
63+
64+
//These two values dictate what particles it accepts as combinations
65+
particleSumTo = 0;
66+
particleProdTo = 1;
67+
for (const int i : particleID) {
68+
particleSumTo += i;
69+
particleProdTo *= i;
70+
}
71+
72+
// if any of the vectors are of size 1, take that to mean it is a new default
73+
double defaultPtMin = 1.8;
74+
if ((int)ptMin.size() == 1) {
75+
defaultPtMin = ptMin[0];
76+
}
77+
78+
if ((int)ptMin.size() < nParticles) {
79+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given pT value size"
80+
"< size of the number of particle IDs."
81+
" Filling remaining values with "
82+
<< defaultPtMin << endl;
83+
while ((int)ptMin.size() < nParticles) {
84+
ptMin.push_back(defaultPtMin);
85+
}
86+
} else if ((int)ptMin.size() > nParticles) {
87+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given pT value size"
88+
"> size of the number of particle IDs."
89+
" Ignoring extraneous values "
90+
<< endl;
91+
ptMin.resize(nParticles);
92+
}
93+
94+
double defaultEtaMax = 2.7;
95+
if ((int)etaMax.size() == 1) {
96+
defaultEtaMax = etaMax[0];
97+
}
98+
if ((int)etaMax.size() < nParticles) {
99+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given eta value size"
100+
"< size of the number of particle IDs."
101+
" Filling remaining values with "
102+
<< defaultEtaMax << endl;
103+
while ((int)etaMax.size() < nParticles) {
104+
etaMax.push_back(defaultEtaMax);
105+
}
106+
} else if ((int)etaMax.size() > nParticles) {
107+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given eta value size"
108+
"> size of the number of particle IDs."
109+
" Ignoring extraneous values "
110+
<< endl;
111+
etaMax.resize(nParticles);
112+
}
113+
114+
int defaultStatus = 1;
115+
if ((int)status.size() == 1) {
116+
defaultStatus = status[0];
117+
}
118+
if ((int)status.size() < nParticles) {
119+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given status value size"
120+
"< size of the number of particle IDs."
121+
" Filling remaining values with "
122+
<< defaultStatus << endl;
123+
while ((int)status.size() < nParticles) {
124+
status.push_back(defaultStatus);
125+
}
126+
} else if ((int)status.size() > nParticles) {
127+
edm::LogWarning("MCMultiParticleMassFilter") << "Warning: Given status value size"
128+
"> size of the number of particle IDs."
129+
" Ignoring extraneous values "
130+
<< endl;
131+
status.resize(nParticles);
132+
}
133+
134+
for (int i = 0; i < nParticles; i++) {
135+
std::tuple<double, double, int> cutForParticle = std::make_tuple(ptMin[i], etaMax[i], status[i]);
136+
cutPerParticle[particleID[i]] = cutForParticle;
137+
} //assign the set of cuts you decided upon matched to each ID value in order
138+
}
139+
140+
MCMultiParticleMassFilter::~MCMultiParticleMassFilter() {}
141+
142+
bool MCMultiParticleMassFilter::filter(edm::StreamID, edm::Event& iEvent, const edm::EventSetup&) const {
143+
edm::Handle<edm::HepMCProduct> evt;
144+
iEvent.getByToken(token_, evt);
145+
const HepMC::GenEvent* myGenEvent = evt->GetEvent();
146+
147+
std::vector<HepMC::GenParticle*> particlesThatPassCuts = std::vector<HepMC::GenParticle*>();
148+
for (HepMC::GenEvent::particle_const_iterator p = myGenEvent->particles_begin(); p != myGenEvent->particles_end();
149+
++p) {
150+
for (const int i : particleID) {
151+
if (i == (*p)->pdg_id()) {
152+
//if the particle ID is one of the ones you specified, check for cuts per ID
153+
const auto cuts = cutPerParticle.at(i);
154+
if (((*p)->status() == get<2>(cuts)) && ((*p)->momentum().perp() >= get<0>(cuts)) &&
155+
(std::fabs((*p)->momentum().eta()) <= get<1>(cuts))) {
156+
particlesThatPassCuts.push_back(*p);
157+
break;
158+
}
159+
}
160+
}
161+
}
162+
int nIterables = particlesThatPassCuts.size();
163+
if (nIterables < nParticles) {
164+
return false;
165+
} else {
166+
int i = 0;
167+
//only iterate while there are enough particles that pass cuts
168+
while ((nIterables - i) >= nParticles) {
169+
vector<int> indices;
170+
//start recursing from index 0, 1, 2, ...
171+
indices.push_back(i);
172+
bool success = recurseLoop(particlesThatPassCuts, indices, 1);
173+
if (success) {
174+
return true;
175+
}
176+
i++;
177+
}
178+
}
179+
return false;
180+
}
181+
182+
bool MCMultiParticleMassFilter::recurseLoop(std::vector<HepMC::GenParticle*>& particlesThatPassCuts,
183+
std::vector<int> indices,
184+
int depth) const {
185+
int lastIndex = indices.back();
186+
int nIterables = (int)(particlesThatPassCuts.size());
187+
if (lastIndex >= nIterables) {
188+
return false;
189+
} else if (depth == nParticles) {
190+
//you have the right number of particles!
191+
int tempSum = 0;
192+
int tempProd = 1;
193+
194+
double px, py, pz, e;
195+
px = py = pz = e = 0;
196+
for (const int i : indices) {
197+
int id = particlesThatPassCuts[i]->pdg_id();
198+
tempSum += id;
199+
tempProd *= id;
200+
HepMC::FourVector tempVec = particlesThatPassCuts[i]->momentum();
201+
px += tempVec.px();
202+
py += tempVec.py();
203+
pz += tempVec.pz();
204+
e += tempVec.e();
205+
}
206+
if ((tempSum != particleSumTo) || (tempProd != particleProdTo)) {
207+
return false; //check if the ids are what you want
208+
}
209+
double invMassSq = e * e - px * px - py * py - pz * pz;
210+
//taking the root is computationally expensive, so use the squared term
211+
if ((invMassSq >= minTotalMassSq) && (invMassSq <= maxTotalMassSq)) {
212+
return true;
213+
}
214+
return false;
215+
} else {
216+
vector<bool> recursionResult;
217+
//propagate recursion across all combinations of remaining indices
218+
for (int i = 1; i < nIterables - lastIndex; i++) {
219+
vector<int> newIndices = indices;
220+
newIndices.push_back(lastIndex + i);
221+
//always up the depth by 1 to make sure there is no infinite recursion
222+
recursionResult.push_back(recurseLoop(particlesThatPassCuts, newIndices, depth + 1));
223+
}
224+
//search the results to look for one successful combination
225+
for (bool r : recursionResult) {
226+
if (r) {
227+
return true;
228+
}
229+
}
230+
return false;
231+
}
232+
}
233+
DEFINE_FWK_MODULE(MCMultiParticleMassFilter);
234+
235+

0 commit comments

Comments
 (0)