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