CMS 3D CMS Logo

TtFullLepKinSolutionProducer.cc
Go to the documentation of this file.
1 #include <memory>
2 #include <string>
3 #include <vector>
4 #include "TLorentzVector.h"
13 
15 public:
16  explicit TtFullLepKinSolutionProducer(const edm::ParameterSet& iConfig);
17  ~TtFullLepKinSolutionProducer() override = default;
18 
19  void produce(edm::Event& evt, const edm::EventSetup& iSetup) override;
20 
21 private:
22  // next methods are avoidable but they make the code legible
23  inline bool PTComp(const reco::Candidate*, const reco::Candidate*) const;
24  inline bool LepDiffCharge(const reco::Candidate*, const reco::Candidate*) const;
25  inline bool HasPositiveCharge(const reco::Candidate*) const;
26 
27  struct Compare {
28  bool operator()(std::pair<double, int> a, std::pair<double, int> b) { return a.first > b.first; }
29  };
30 
35 
40  std::vector<double> nupars_;
41 
42  std::unique_ptr<TtFullLepKinSolver> solver;
43 };
44 
45 inline bool TtFullLepKinSolutionProducer::PTComp(const reco::Candidate* l1, const reco::Candidate* l2) const {
46  return (l1->pt() > l2->pt());
47 }
48 
50  return (l1->charge() != l2->charge());
51 }
52 
54  return (l->charge() > 0);
55 }
56 
58  // configurables
59  jetsToken_ = consumes<std::vector<pat::Jet> >(iConfig.getParameter<edm::InputTag>("jets"));
60  electronsToken_ = consumes<std::vector<pat::Electron> >(iConfig.getParameter<edm::InputTag>("electrons"));
61  muonsToken_ = consumes<std::vector<pat::Muon> >(iConfig.getParameter<edm::InputTag>("muons"));
62  metsToken_ = consumes<std::vector<pat::MET> >(iConfig.getParameter<edm::InputTag>("mets"));
63  jetCorrLevel_ = iConfig.getParameter<std::string>("jetCorrectionLevel");
64  maxNJets_ = iConfig.getParameter<int>("maxNJets");
65  maxNComb_ = iConfig.getParameter<int>("maxNComb");
66  eeChannel_ = iConfig.getParameter<bool>("eeChannel");
67  emuChannel_ = iConfig.getParameter<bool>("emuChannel");
68  mumuChannel_ = iConfig.getParameter<bool>("mumuChannel");
69  searchWrongCharge_ = iConfig.getParameter<bool>("searchWrongCharge");
70  tmassbegin_ = iConfig.getParameter<double>("tmassbegin");
71  tmassend_ = iConfig.getParameter<double>("tmassend");
72  tmassstep_ = iConfig.getParameter<double>("tmassstep");
73  nupars_ = iConfig.getParameter<std::vector<double> >("neutrino_parameters");
74 
75  // define what will be produced
76  produces<std::vector<std::vector<int> > >(); // vector of the particle inices (b, bbar, e1, e2, mu1, mu2)
77  produces<std::vector<reco::LeafCandidate> >("fullLepNeutrinos");
78  produces<std::vector<reco::LeafCandidate> >("fullLepNeutrinoBars");
79  produces<std::vector<double> >("solWeight"); //weight for a specific kin solution
80  produces<bool>("isWrongCharge"); //true if leptons have the same charge
81 
82  solver = std::make_unique<TtFullLepKinSolver>(tmassbegin_, tmassend_, tmassstep_, nupars_);
83 }
84 
86  //create vectors fo runsorted output
87  std::vector<std::vector<int> > idcsV;
88  std::vector<reco::LeafCandidate> nusV;
89  std::vector<reco::LeafCandidate> nuBarsV;
90  std::vector<std::pair<double, int> > weightsV;
91 
92  //create pointer for products
93  std::unique_ptr<std::vector<std::vector<int> > > pIdcs(new std::vector<std::vector<int> >);
94  std::unique_ptr<std::vector<reco::LeafCandidate> > pNus(new std::vector<reco::LeafCandidate>);
95  std::unique_ptr<std::vector<reco::LeafCandidate> > pNuBars(new std::vector<reco::LeafCandidate>);
96  std::unique_ptr<std::vector<double> > pWeight(new std::vector<double>);
97  std::unique_ptr<bool> pWrongCharge(new bool);
98 
103 
104  int selMuon1 = -1, selMuon2 = -1;
105  int selElectron1 = -1, selElectron2 = -1;
106  bool ee = false;
107  bool emu = false;
108  bool mumu = false;
109  bool isWrongCharge = false;
110  bool jetsFound = false;
111  bool METFound = false;
112  bool electronsFound = false;
113  bool electronMuonFound = false;
114  bool muonsFound = false;
115 
116  //select Jets (TopJet vector is sorted on ET)
117  if (jets->size() >= 2) {
118  jetsFound = true;
119  }
120 
121  //select MET (TopMET vector is sorted on ET)
122  if (!mets->empty()) {
123  METFound = true;
124  }
125 
126  // If we have electrons and muons available,
127  // build a solutions with electrons and muons.
128  if (muons->size() + electrons->size() >= 2) {
129  // select leptons
130  if (electrons->empty())
131  mumu = true;
132  else if (muons->empty())
133  ee = true;
134  else if (electrons->size() == 1) {
135  if (muons->size() == 1)
136  emu = true;
137  else if (PTComp(&(*electrons)[0], &(*muons)[1]))
138  emu = true;
139  else
140  mumu = true;
141  } else if (electrons->size() > 1) {
142  if (PTComp(&(*electrons)[1], &(*muons)[0]))
143  ee = true;
144  else if (muons->size() == 1)
145  emu = true;
146  else if (PTComp(&(*electrons)[0], &(*muons)[1]))
147  emu = true;
148  else
149  mumu = true;
150  }
151  if (ee && eeChannel_) {
152  if (LepDiffCharge(&(*electrons)[0], &(*electrons)[1]) || searchWrongCharge_) {
153  if (HasPositiveCharge(&(*electrons)[0]) || !LepDiffCharge(&(*electrons)[0], &(*electrons)[1])) {
154  selElectron1 = 0;
155  selElectron2 = 1;
156  } else {
157  selElectron1 = 1;
158  selElectron2 = 0;
159  }
160  electronsFound = true;
161  if (!LepDiffCharge(&(*electrons)[0], &(*electrons)[1]))
162  isWrongCharge = true;
163  }
164  } else if (emu && emuChannel_) {
165  if (LepDiffCharge(&(*electrons)[0], &(*muons)[0]) || searchWrongCharge_) {
166  selElectron1 = 0;
167  selMuon1 = 0;
168  electronMuonFound = true;
169  if (!LepDiffCharge(&(*electrons)[0], &(*muons)[0]))
170  isWrongCharge = true;
171  }
172  } else if (mumu && mumuChannel_) {
173  if (LepDiffCharge(&(*muons)[0], &(*muons)[1]) || searchWrongCharge_) {
174  if (HasPositiveCharge(&(*muons)[0]) || !LepDiffCharge(&(*muons)[0], &(*muons)[1])) {
175  selMuon1 = 0;
176  selMuon2 = 1;
177  } else {
178  selMuon1 = 1;
179  selMuon2 = 0;
180  }
181  muonsFound = true;
182  if (!LepDiffCharge(&(*muons)[0], &(*muons)[1]))
183  isWrongCharge = true;
184  }
185  }
186  }
187 
188  *pWrongCharge = isWrongCharge;
189 
190  // Check that the above work makes sense
191  if (int(ee) + int(emu) + int(mumu) > 1) {
192  edm::LogWarning("TtFullLepKinSolutionProducer") << "Lepton selection criteria uncorrectly defined";
193  }
194 
195  // Check if the leptons for the required Channel are available
196  bool correctLeptons =
197  ((electronsFound && eeChannel_) || (muonsFound && mumuChannel_) || (electronMuonFound && emuChannel_));
198  // Check for equally charged leptons if for wrong charge combinations is searched
199  if (isWrongCharge) {
200  correctLeptons = correctLeptons && searchWrongCharge_;
201  }
202 
203  if (correctLeptons && METFound && jetsFound) {
204  // run over all jets if input parameter maxNJets is -1 or
205  // adapt maxNJets if number of present jets is smaller than selected
206  // number of jets
207  int stop = maxNJets_;
208  if (jets->size() < static_cast<unsigned int>(stop) || stop < 0)
209  stop = jets->size();
210 
211  // counter for number of found kinematic solutions
212  int nSol = 0;
213 
214  // consider all permutations
215  for (int ib = 0; ib < stop; ib++) {
216  // second loop of the permutations
217  for (int ibbar = 0; ibbar < stop; ibbar++) {
218  // avoid the diagonal: b and bbar must be distinct jets
219  if (ib == ibbar)
220  continue;
221 
222  std::vector<int> idcs;
223 
224  // push back the indices of the jets
225  idcs.push_back(ib);
226  idcs.push_back(ibbar);
227 
228  TLorentzVector LV_l1;
229  TLorentzVector LV_l2;
230  TLorentzVector LV_b = TLorentzVector((*jets)[ib].correctedJet(jetCorrLevel_, "bottom").px(),
231  (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").py(),
232  (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").pz(),
233  (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").energy());
234  TLorentzVector LV_bbar = TLorentzVector((*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").px(),
235  (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").py(),
236  (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").pz(),
237  (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").energy());
238 
239  double xconstraint = 0, yconstraint = 0;
240 
241  if (ee) {
242  idcs.push_back(selElectron1);
243  LV_l1.SetXYZT((*electrons)[selElectron1].px(),
244  (*electrons)[selElectron1].py(),
245  (*electrons)[selElectron1].pz(),
246  (*electrons)[selElectron1].energy());
247  xconstraint += (*electrons)[selElectron1].px();
248  yconstraint += (*electrons)[selElectron1].py();
249 
250  idcs.push_back(selElectron2);
251  LV_l2.SetXYZT((*electrons)[selElectron2].px(),
252  (*electrons)[selElectron2].py(),
253  (*electrons)[selElectron2].pz(),
254  (*electrons)[selElectron2].energy());
255  xconstraint += (*electrons)[selElectron2].px();
256  yconstraint += (*electrons)[selElectron2].py();
257 
258  idcs.push_back(-1);
259  idcs.push_back(-1);
260  }
261 
262  else if (emu) {
263  if (!isWrongCharge) {
264  if (HasPositiveCharge(&(*electrons)[selElectron1])) {
265  idcs.push_back(selElectron1);
266  LV_l1.SetXYZT((*electrons)[selElectron1].px(),
267  (*electrons)[selElectron1].py(),
268  (*electrons)[selElectron1].pz(),
269  (*electrons)[selElectron1].energy());
270  xconstraint += (*electrons)[selElectron1].px();
271  yconstraint += (*electrons)[selElectron1].py();
272 
273  idcs.push_back(-1);
274  idcs.push_back(-1);
275 
276  idcs.push_back(selMuon1);
277  LV_l2.SetXYZT((*muons)[selMuon1].px(),
278  (*muons)[selMuon1].py(),
279  (*muons)[selMuon1].pz(),
280  (*muons)[selMuon1].energy());
281  xconstraint += (*muons)[selMuon1].px();
282  yconstraint += (*muons)[selMuon1].py();
283  } else {
284  idcs.push_back(-1);
285 
286  idcs.push_back(selMuon1);
287  LV_l1.SetXYZT((*muons)[selMuon1].px(),
288  (*muons)[selMuon1].py(),
289  (*muons)[selMuon1].pz(),
290  (*muons)[selMuon1].energy());
291  xconstraint += (*muons)[selMuon1].px();
292  yconstraint += (*muons)[selMuon1].py();
293 
294  idcs.push_back(selElectron1);
295  LV_l2.SetXYZT((*electrons)[selElectron1].px(),
296  (*electrons)[selElectron1].py(),
297  (*electrons)[selElectron1].pz(),
298  (*electrons)[selElectron1].energy());
299  xconstraint += (*electrons)[selElectron1].px();
300  yconstraint += (*electrons)[selElectron1].py();
301 
302  idcs.push_back(-1);
303  }
304  } else { // means "if wrong charge"
305  if (HasPositiveCharge(&(*electrons)[selElectron1])) { // both leps positive
306  idcs.push_back(selElectron1);
307  LV_l1.SetXYZT((*electrons)[selElectron1].px(),
308  (*electrons)[selElectron1].py(),
309  (*electrons)[selElectron1].pz(),
310  (*electrons)[selElectron1].energy());
311  xconstraint += (*electrons)[selElectron1].px();
312  yconstraint += (*electrons)[selElectron1].py();
313 
314  idcs.push_back(-1);
315 
316  idcs.push_back(selMuon1);
317  LV_l2.SetXYZT((*muons)[selMuon1].px(),
318  (*muons)[selMuon1].py(),
319  (*muons)[selMuon1].pz(),
320  (*muons)[selMuon1].energy());
321  xconstraint += (*muons)[selMuon1].px();
322  yconstraint += (*muons)[selMuon1].py();
323 
324  idcs.push_back(-1);
325  } else { // both leps negative
326  idcs.push_back(-1);
327 
328  idcs.push_back(selElectron1);
329  LV_l2.SetXYZT((*electrons)[selElectron1].px(),
330  (*electrons)[selElectron1].py(),
331  (*electrons)[selElectron1].pz(),
332  (*electrons)[selElectron1].energy());
333  xconstraint += (*electrons)[selElectron1].px();
334  yconstraint += (*electrons)[selElectron1].py();
335 
336  idcs.push_back(-1);
337 
338  idcs.push_back(selMuon1);
339  LV_l1.SetXYZT((*muons)[selMuon1].px(),
340  (*muons)[selMuon1].py(),
341  (*muons)[selMuon1].pz(),
342  (*muons)[selMuon1].energy());
343  xconstraint += (*muons)[selMuon1].px();
344  yconstraint += (*muons)[selMuon1].py();
345  }
346  }
347  }
348 
349  else if (mumu) {
350  idcs.push_back(-1);
351  idcs.push_back(-1);
352 
353  idcs.push_back(selMuon1);
354  LV_l1.SetXYZT(
355  (*muons)[selMuon1].px(), (*muons)[selMuon1].py(), (*muons)[selMuon1].pz(), (*muons)[selMuon1].energy());
356  xconstraint += (*muons)[selMuon1].px();
357  yconstraint += (*muons)[selMuon1].py();
358 
359  idcs.push_back(selMuon2);
360  LV_l2.SetXYZT(
361  (*muons)[selMuon2].px(), (*muons)[selMuon2].py(), (*muons)[selMuon2].pz(), (*muons)[selMuon2].energy());
362  xconstraint += (*muons)[selMuon2].px();
363  yconstraint += (*muons)[selMuon2].py();
364  }
365 
366  xconstraint += (*jets)[ib].px() + (*jets)[ibbar].px() + (*mets)[0].px();
367  yconstraint += (*jets)[ib].py() + (*jets)[ibbar].py() + (*mets)[0].py();
368 
369  // calculate neutrino momenta and eventweight
370  solver->SetConstraints(xconstraint, yconstraint);
371  TtFullLepKinSolver::NeutrinoSolution nuSol = solver->getNuSolution(LV_l1, LV_l2, LV_b, LV_bbar);
372 
373  // add solution to the vectors of solutions if solution exists
374  if (nuSol.weight > 0) {
375  // add the leptons and jets indices to the vector of combinations
376  idcsV.push_back(idcs);
377 
378  // add the neutrinos
379  nusV.push_back(nuSol.neutrino);
380  nuBarsV.push_back(nuSol.neutrinoBar);
381 
382  // add the solution weight
383  weightsV.push_back(std::make_pair(nuSol.weight, nSol));
384 
385  nSol++;
386  }
387  }
388  }
389  }
390 
391  if (weightsV.empty()) {
392  //create dmummy vector
393  std::vector<int> idcs;
394  idcs.reserve(6);
395  for (int i = 0; i < 6; ++i)
396  idcs.push_back(-1);
397 
398  idcsV.push_back(idcs);
399  weightsV.push_back(std::make_pair(-1, 0));
401  nusV.push_back(nu);
402  reco::LeafCandidate nuBar;
403  nuBarsV.push_back(nuBar);
404  }
405 
406  // check if all vectors have correct length
407  int weightL = weightsV.size();
408  int nuL = nusV.size();
409  int nuBarL = nuBarsV.size();
410  int idxL = idcsV.size();
411 
412  if (weightL != nuL || weightL != nuBarL || weightL != idxL) {
413  edm::LogWarning("TtFullLepKinSolutionProducer")
414  << "Output vectors are of different length:"
415  << "\n weight: " << weightL << "\n nu: " << nuL << "\n nubar: " << nuBarL << "\n idcs: " << idxL;
416  }
417 
418  // sort vectors by weight in decreasing order
419  if (weightsV.size() > 1) {
420  sort(weightsV.begin(), weightsV.end(), Compare());
421  }
422 
423  // determine the number of solutions which is written in the event
424  int stop = weightL;
425  if (maxNComb_ > 0 && maxNComb_ < stop)
426  stop = maxNComb_;
427 
428  for (int i = 0; i < stop; ++i) {
429  pWeight->push_back(weightsV[i].first);
430  pNus->push_back(nusV[weightsV[i].second]);
431  pNuBars->push_back(nuBarsV[weightsV[i].second]);
432  pIdcs->push_back(idcsV[weightsV[i].second]);
433  }
434 
435  // put the results in the event
436  evt.put(std::move(pIdcs));
437  evt.put(std::move(pNus), "fullLepNeutrinos");
438  evt.put(std::move(pNuBars), "fullLepNeutrinoBars");
439  evt.put(std::move(pWeight), "solWeight");
440  evt.put(std::move(pWrongCharge), "isWrongCharge");
441 }
442 
bool operator()(std::pair< double, int > a, std::pair< double, int > b)
edm::EDGetTokenT< std::vector< pat::Muon > > muonsToken_
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:133
std::unique_ptr< TtFullLepKinSolver > solver
virtual double pt() const =0
transverse momentum
~TtFullLepKinSolutionProducer() override=default
U second(std::pair< T, U > const &p)
void produce(edm::Event &evt, const edm::EventSetup &iSetup) override
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
bool LepDiffCharge(const reco::Candidate *, const reco::Candidate *) const
virtual int charge() const =0
electric charge
edm::EDGetTokenT< std::vector< pat::MET > > metsToken_
edm::EDGetTokenT< std::vector< pat::Jet > > jetsToken_
bool HasPositiveCharge(const reco::Candidate *) const
double b
Definition: hdecay.h:120
TtFullLepKinSolutionProducer(const edm::ParameterSet &iConfig)
edm::EDGetTokenT< std::vector< pat::Electron > > electronsToken_
Handle< PROD > getHandle(EDGetTokenT< PROD > token) const
Definition: Event.h:552
double a
Definition: hdecay.h:121
bool PTComp(const reco::Candidate *, const reco::Candidate *) const
Log< level::Warning, false > LogWarning
def move(src, dest)
Definition: eostools.py:511
ib
Definition: cuy.py:661