File indexing completed on 2024-04-06 12:31:22
0001 #include <memory>
0002 #include <string>
0003 #include <vector>
0004 #include "TLorentzVector.h"
0005 #include "DataFormats/Math/interface/deltaR.h"
0006 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0007 #include "FWCore/Framework/interface/stream/EDProducer.h"
0008 #include "FWCore/Framework/interface/Event.h"
0009 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0010 #include "FWCore/Utilities/interface/InputTag.h"
0011 #include "DataFormats/Candidate/interface/LeafCandidate.h"
0012 #include "TopQuarkAnalysis/TopKinFitter/interface/TtFullLepKinSolver.h"
0013
0014 class TtFullLepKinSolutionProducer : public edm::stream::EDProducer<> {
0015 public:
0016 explicit TtFullLepKinSolutionProducer(const edm::ParameterSet& iConfig);
0017 ~TtFullLepKinSolutionProducer() override = default;
0018
0019 void produce(edm::Event& evt, const edm::EventSetup& iSetup) override;
0020
0021 private:
0022
0023 inline bool PTComp(const reco::Candidate*, const reco::Candidate*) const;
0024 inline bool LepDiffCharge(const reco::Candidate*, const reco::Candidate*) const;
0025 inline bool HasPositiveCharge(const reco::Candidate*) const;
0026
0027 struct Compare {
0028 bool operator()(std::pair<double, int> a, std::pair<double, int> b) { return a.first > b.first; }
0029 };
0030
0031 edm::EDGetTokenT<std::vector<pat::Jet> > jetsToken_;
0032 edm::EDGetTokenT<std::vector<pat::Electron> > electronsToken_;
0033 edm::EDGetTokenT<std::vector<pat::Muon> > muonsToken_;
0034 edm::EDGetTokenT<std::vector<pat::MET> > metsToken_;
0035
0036 std::string jetCorrLevel_;
0037 int maxNJets_, maxNComb_;
0038 bool eeChannel_, emuChannel_, mumuChannel_, searchWrongCharge_;
0039 double tmassbegin_, tmassend_, tmassstep_;
0040 std::vector<double> nupars_;
0041
0042 std::unique_ptr<TtFullLepKinSolver> solver;
0043 };
0044
0045 inline bool TtFullLepKinSolutionProducer::PTComp(const reco::Candidate* l1, const reco::Candidate* l2) const {
0046 return (l1->pt() > l2->pt());
0047 }
0048
0049 inline bool TtFullLepKinSolutionProducer::LepDiffCharge(const reco::Candidate* l1, const reco::Candidate* l2) const {
0050 return (l1->charge() != l2->charge());
0051 }
0052
0053 inline bool TtFullLepKinSolutionProducer::HasPositiveCharge(const reco::Candidate* l) const {
0054 return (l->charge() > 0);
0055 }
0056
0057 inline TtFullLepKinSolutionProducer::TtFullLepKinSolutionProducer(const edm::ParameterSet& iConfig) {
0058
0059 jetsToken_ = consumes<std::vector<pat::Jet> >(iConfig.getParameter<edm::InputTag>("jets"));
0060 electronsToken_ = consumes<std::vector<pat::Electron> >(iConfig.getParameter<edm::InputTag>("electrons"));
0061 muonsToken_ = consumes<std::vector<pat::Muon> >(iConfig.getParameter<edm::InputTag>("muons"));
0062 metsToken_ = consumes<std::vector<pat::MET> >(iConfig.getParameter<edm::InputTag>("mets"));
0063 jetCorrLevel_ = iConfig.getParameter<std::string>("jetCorrectionLevel");
0064 maxNJets_ = iConfig.getParameter<int>("maxNJets");
0065 maxNComb_ = iConfig.getParameter<int>("maxNComb");
0066 eeChannel_ = iConfig.getParameter<bool>("eeChannel");
0067 emuChannel_ = iConfig.getParameter<bool>("emuChannel");
0068 mumuChannel_ = iConfig.getParameter<bool>("mumuChannel");
0069 searchWrongCharge_ = iConfig.getParameter<bool>("searchWrongCharge");
0070 tmassbegin_ = iConfig.getParameter<double>("tmassbegin");
0071 tmassend_ = iConfig.getParameter<double>("tmassend");
0072 tmassstep_ = iConfig.getParameter<double>("tmassstep");
0073 nupars_ = iConfig.getParameter<std::vector<double> >("neutrino_parameters");
0074
0075
0076 produces<std::vector<std::vector<int> > >();
0077 produces<std::vector<reco::LeafCandidate> >("fullLepNeutrinos");
0078 produces<std::vector<reco::LeafCandidate> >("fullLepNeutrinoBars");
0079 produces<std::vector<double> >("solWeight");
0080 produces<bool>("isWrongCharge");
0081
0082 solver = std::make_unique<TtFullLepKinSolver>(tmassbegin_, tmassend_, tmassstep_, nupars_);
0083 }
0084
0085 inline void TtFullLepKinSolutionProducer::produce(edm::Event& evt, const edm::EventSetup& iSetup) {
0086
0087 std::vector<std::vector<int> > idcsV;
0088 std::vector<reco::LeafCandidate> nusV;
0089 std::vector<reco::LeafCandidate> nuBarsV;
0090 std::vector<std::pair<double, int> > weightsV;
0091
0092
0093 std::unique_ptr<std::vector<std::vector<int> > > pIdcs(new std::vector<std::vector<int> >);
0094 std::unique_ptr<std::vector<reco::LeafCandidate> > pNus(new std::vector<reco::LeafCandidate>);
0095 std::unique_ptr<std::vector<reco::LeafCandidate> > pNuBars(new std::vector<reco::LeafCandidate>);
0096 std::unique_ptr<std::vector<double> > pWeight(new std::vector<double>);
0097 std::unique_ptr<bool> pWrongCharge(new bool);
0098
0099 const edm::Handle<std::vector<pat::Jet> >& jets = evt.getHandle(jetsToken_);
0100 const edm::Handle<std::vector<pat::Electron> >& electrons = evt.getHandle(electronsToken_);
0101 const edm::Handle<std::vector<pat::Muon> >& muons = evt.getHandle(muonsToken_);
0102 const edm::Handle<std::vector<pat::MET> >& mets = evt.getHandle(metsToken_);
0103
0104 int selMuon1 = -1, selMuon2 = -1;
0105 int selElectron1 = -1, selElectron2 = -1;
0106 bool ee = false;
0107 bool emu = false;
0108 bool mumu = false;
0109 bool isWrongCharge = false;
0110 bool jetsFound = false;
0111 bool METFound = false;
0112 bool electronsFound = false;
0113 bool electronMuonFound = false;
0114 bool muonsFound = false;
0115
0116
0117 if (jets->size() >= 2) {
0118 jetsFound = true;
0119 }
0120
0121
0122 if (!mets->empty()) {
0123 METFound = true;
0124 }
0125
0126
0127
0128 if (muons->size() + electrons->size() >= 2) {
0129
0130 if (electrons->empty())
0131 mumu = true;
0132 else if (muons->empty())
0133 ee = true;
0134 else if (electrons->size() == 1) {
0135 if (muons->size() == 1)
0136 emu = true;
0137 else if (PTComp(&(*electrons)[0], &(*muons)[1]))
0138 emu = true;
0139 else
0140 mumu = true;
0141 } else if (electrons->size() > 1) {
0142 if (PTComp(&(*electrons)[1], &(*muons)[0]))
0143 ee = true;
0144 else if (muons->size() == 1)
0145 emu = true;
0146 else if (PTComp(&(*electrons)[0], &(*muons)[1]))
0147 emu = true;
0148 else
0149 mumu = true;
0150 }
0151 if (ee && eeChannel_) {
0152 if (LepDiffCharge(&(*electrons)[0], &(*electrons)[1]) || searchWrongCharge_) {
0153 if (HasPositiveCharge(&(*electrons)[0]) || !LepDiffCharge(&(*electrons)[0], &(*electrons)[1])) {
0154 selElectron1 = 0;
0155 selElectron2 = 1;
0156 } else {
0157 selElectron1 = 1;
0158 selElectron2 = 0;
0159 }
0160 electronsFound = true;
0161 if (!LepDiffCharge(&(*electrons)[0], &(*electrons)[1]))
0162 isWrongCharge = true;
0163 }
0164 } else if (emu && emuChannel_) {
0165 if (LepDiffCharge(&(*electrons)[0], &(*muons)[0]) || searchWrongCharge_) {
0166 selElectron1 = 0;
0167 selMuon1 = 0;
0168 electronMuonFound = true;
0169 if (!LepDiffCharge(&(*electrons)[0], &(*muons)[0]))
0170 isWrongCharge = true;
0171 }
0172 } else if (mumu && mumuChannel_) {
0173 if (LepDiffCharge(&(*muons)[0], &(*muons)[1]) || searchWrongCharge_) {
0174 if (HasPositiveCharge(&(*muons)[0]) || !LepDiffCharge(&(*muons)[0], &(*muons)[1])) {
0175 selMuon1 = 0;
0176 selMuon2 = 1;
0177 } else {
0178 selMuon1 = 1;
0179 selMuon2 = 0;
0180 }
0181 muonsFound = true;
0182 if (!LepDiffCharge(&(*muons)[0], &(*muons)[1]))
0183 isWrongCharge = true;
0184 }
0185 }
0186 }
0187
0188 *pWrongCharge = isWrongCharge;
0189
0190
0191 if (int(ee) + int(emu) + int(mumu) > 1) {
0192 edm::LogWarning("TtFullLepKinSolutionProducer") << "Lepton selection criteria uncorrectly defined";
0193 }
0194
0195
0196 bool correctLeptons =
0197 ((electronsFound && eeChannel_) || (muonsFound && mumuChannel_) || (electronMuonFound && emuChannel_));
0198
0199 if (isWrongCharge) {
0200 correctLeptons = correctLeptons && searchWrongCharge_;
0201 }
0202
0203 if (correctLeptons && METFound && jetsFound) {
0204
0205
0206
0207 int stop = maxNJets_;
0208 if (jets->size() < static_cast<unsigned int>(stop) || stop < 0)
0209 stop = jets->size();
0210
0211
0212 int nSol = 0;
0213
0214
0215 for (int ib = 0; ib < stop; ib++) {
0216
0217 for (int ibbar = 0; ibbar < stop; ibbar++) {
0218
0219 if (ib == ibbar)
0220 continue;
0221
0222 std::vector<int> idcs;
0223
0224
0225 idcs.push_back(ib);
0226 idcs.push_back(ibbar);
0227
0228 TLorentzVector LV_l1;
0229 TLorentzVector LV_l2;
0230 TLorentzVector LV_b = TLorentzVector((*jets)[ib].correctedJet(jetCorrLevel_, "bottom").px(),
0231 (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").py(),
0232 (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").pz(),
0233 (*jets)[ib].correctedJet(jetCorrLevel_, "bottom").energy());
0234 TLorentzVector LV_bbar = TLorentzVector((*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").px(),
0235 (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").py(),
0236 (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").pz(),
0237 (*jets)[ibbar].correctedJet(jetCorrLevel_, "bottom").energy());
0238
0239 double xconstraint = 0, yconstraint = 0;
0240
0241 if (ee) {
0242 idcs.push_back(selElectron1);
0243 LV_l1.SetXYZT((*electrons)[selElectron1].px(),
0244 (*electrons)[selElectron1].py(),
0245 (*electrons)[selElectron1].pz(),
0246 (*electrons)[selElectron1].energy());
0247 xconstraint += (*electrons)[selElectron1].px();
0248 yconstraint += (*electrons)[selElectron1].py();
0249
0250 idcs.push_back(selElectron2);
0251 LV_l2.SetXYZT((*electrons)[selElectron2].px(),
0252 (*electrons)[selElectron2].py(),
0253 (*electrons)[selElectron2].pz(),
0254 (*electrons)[selElectron2].energy());
0255 xconstraint += (*electrons)[selElectron2].px();
0256 yconstraint += (*electrons)[selElectron2].py();
0257
0258 idcs.push_back(-1);
0259 idcs.push_back(-1);
0260 }
0261
0262 else if (emu) {
0263 if (!isWrongCharge) {
0264 if (HasPositiveCharge(&(*electrons)[selElectron1])) {
0265 idcs.push_back(selElectron1);
0266 LV_l1.SetXYZT((*electrons)[selElectron1].px(),
0267 (*electrons)[selElectron1].py(),
0268 (*electrons)[selElectron1].pz(),
0269 (*electrons)[selElectron1].energy());
0270 xconstraint += (*electrons)[selElectron1].px();
0271 yconstraint += (*electrons)[selElectron1].py();
0272
0273 idcs.push_back(-1);
0274 idcs.push_back(-1);
0275
0276 idcs.push_back(selMuon1);
0277 LV_l2.SetXYZT((*muons)[selMuon1].px(),
0278 (*muons)[selMuon1].py(),
0279 (*muons)[selMuon1].pz(),
0280 (*muons)[selMuon1].energy());
0281 xconstraint += (*muons)[selMuon1].px();
0282 yconstraint += (*muons)[selMuon1].py();
0283 } else {
0284 idcs.push_back(-1);
0285
0286 idcs.push_back(selMuon1);
0287 LV_l1.SetXYZT((*muons)[selMuon1].px(),
0288 (*muons)[selMuon1].py(),
0289 (*muons)[selMuon1].pz(),
0290 (*muons)[selMuon1].energy());
0291 xconstraint += (*muons)[selMuon1].px();
0292 yconstraint += (*muons)[selMuon1].py();
0293
0294 idcs.push_back(selElectron1);
0295 LV_l2.SetXYZT((*electrons)[selElectron1].px(),
0296 (*electrons)[selElectron1].py(),
0297 (*electrons)[selElectron1].pz(),
0298 (*electrons)[selElectron1].energy());
0299 xconstraint += (*electrons)[selElectron1].px();
0300 yconstraint += (*electrons)[selElectron1].py();
0301
0302 idcs.push_back(-1);
0303 }
0304 } else {
0305 if (HasPositiveCharge(&(*electrons)[selElectron1])) {
0306 idcs.push_back(selElectron1);
0307 LV_l1.SetXYZT((*electrons)[selElectron1].px(),
0308 (*electrons)[selElectron1].py(),
0309 (*electrons)[selElectron1].pz(),
0310 (*electrons)[selElectron1].energy());
0311 xconstraint += (*electrons)[selElectron1].px();
0312 yconstraint += (*electrons)[selElectron1].py();
0313
0314 idcs.push_back(-1);
0315
0316 idcs.push_back(selMuon1);
0317 LV_l2.SetXYZT((*muons)[selMuon1].px(),
0318 (*muons)[selMuon1].py(),
0319 (*muons)[selMuon1].pz(),
0320 (*muons)[selMuon1].energy());
0321 xconstraint += (*muons)[selMuon1].px();
0322 yconstraint += (*muons)[selMuon1].py();
0323
0324 idcs.push_back(-1);
0325 } else {
0326 idcs.push_back(-1);
0327
0328 idcs.push_back(selElectron1);
0329 LV_l2.SetXYZT((*electrons)[selElectron1].px(),
0330 (*electrons)[selElectron1].py(),
0331 (*electrons)[selElectron1].pz(),
0332 (*electrons)[selElectron1].energy());
0333 xconstraint += (*electrons)[selElectron1].px();
0334 yconstraint += (*electrons)[selElectron1].py();
0335
0336 idcs.push_back(-1);
0337
0338 idcs.push_back(selMuon1);
0339 LV_l1.SetXYZT((*muons)[selMuon1].px(),
0340 (*muons)[selMuon1].py(),
0341 (*muons)[selMuon1].pz(),
0342 (*muons)[selMuon1].energy());
0343 xconstraint += (*muons)[selMuon1].px();
0344 yconstraint += (*muons)[selMuon1].py();
0345 }
0346 }
0347 }
0348
0349 else if (mumu) {
0350 idcs.push_back(-1);
0351 idcs.push_back(-1);
0352
0353 idcs.push_back(selMuon1);
0354 LV_l1.SetXYZT(
0355 (*muons)[selMuon1].px(), (*muons)[selMuon1].py(), (*muons)[selMuon1].pz(), (*muons)[selMuon1].energy());
0356 xconstraint += (*muons)[selMuon1].px();
0357 yconstraint += (*muons)[selMuon1].py();
0358
0359 idcs.push_back(selMuon2);
0360 LV_l2.SetXYZT(
0361 (*muons)[selMuon2].px(), (*muons)[selMuon2].py(), (*muons)[selMuon2].pz(), (*muons)[selMuon2].energy());
0362 xconstraint += (*muons)[selMuon2].px();
0363 yconstraint += (*muons)[selMuon2].py();
0364 }
0365
0366 xconstraint += (*jets)[ib].px() + (*jets)[ibbar].px() + (*mets)[0].px();
0367 yconstraint += (*jets)[ib].py() + (*jets)[ibbar].py() + (*mets)[0].py();
0368
0369
0370 solver->SetConstraints(xconstraint, yconstraint);
0371 TtFullLepKinSolver::NeutrinoSolution nuSol = solver->getNuSolution(LV_l1, LV_l2, LV_b, LV_bbar);
0372
0373
0374 if (nuSol.weight > 0) {
0375
0376 idcsV.push_back(idcs);
0377
0378
0379 nusV.push_back(nuSol.neutrino);
0380 nuBarsV.push_back(nuSol.neutrinoBar);
0381
0382
0383 weightsV.push_back(std::make_pair(nuSol.weight, nSol));
0384
0385 nSol++;
0386 }
0387 }
0388 }
0389 }
0390
0391 if (weightsV.empty()) {
0392
0393 std::vector<int> idcs;
0394 idcs.reserve(6);
0395 for (int i = 0; i < 6; ++i)
0396 idcs.push_back(-1);
0397
0398 idcsV.push_back(idcs);
0399 weightsV.push_back(std::make_pair(-1, 0));
0400 reco::LeafCandidate nu;
0401 nusV.push_back(nu);
0402 reco::LeafCandidate nuBar;
0403 nuBarsV.push_back(nuBar);
0404 }
0405
0406
0407 int weightL = weightsV.size();
0408 int nuL = nusV.size();
0409 int nuBarL = nuBarsV.size();
0410 int idxL = idcsV.size();
0411
0412 if (weightL != nuL || weightL != nuBarL || weightL != idxL) {
0413 edm::LogWarning("TtFullLepKinSolutionProducer")
0414 << "Output vectors are of different length:"
0415 << "\n weight: " << weightL << "\n nu: " << nuL << "\n nubar: " << nuBarL << "\n idcs: " << idxL;
0416 }
0417
0418
0419 if (weightsV.size() > 1) {
0420 sort(weightsV.begin(), weightsV.end(), Compare());
0421 }
0422
0423
0424 int stop = weightL;
0425 if (maxNComb_ > 0 && maxNComb_ < stop)
0426 stop = maxNComb_;
0427
0428 for (int i = 0; i < stop; ++i) {
0429 pWeight->push_back(weightsV[i].first);
0430 pNus->push_back(nusV[weightsV[i].second]);
0431 pNuBars->push_back(nuBarsV[weightsV[i].second]);
0432 pIdcs->push_back(idcsV[weightsV[i].second]);
0433 }
0434
0435
0436 evt.put(std::move(pIdcs));
0437 evt.put(std::move(pNus), "fullLepNeutrinos");
0438 evt.put(std::move(pNuBars), "fullLepNeutrinoBars");
0439 evt.put(std::move(pWeight), "solWeight");
0440 evt.put(std::move(pWrongCharge), "isWrongCharge");
0441 }
0442
0443 #include "FWCore/Framework/interface/MakerMacros.h"
0444 DEFINE_FWK_MODULE(TtFullLepKinSolutionProducer);