File indexing completed on 2025-06-17 22:42:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <memory>
0023 #include <utility>
0024 #include <vector>
0025 #include <algorithm>
0026
0027
0028 #include "FWCore/Framework/interface/Frameworkfwd.h"
0029 #include "FWCore/Framework/interface/global/EDProducer.h"
0030
0031 #include "FWCore/Framework/interface/Event.h"
0032 #include "FWCore/Framework/interface/MakerMacros.h"
0033
0034 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0035
0036 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0037 #include "FWCore/Framework/interface/ESHandle.h"
0038 #include "FWCore/Framework/interface/EventSetup.h"
0039 #include "FWCore/Utilities/interface/EDPutToken.h"
0040
0041 #include "DataFormats/HepMCCandidate/interface/GenParticle.h"
0042
0043 #include "DataFormats/JetReco/interface/GenJet.h"
0044 #include "DataFormats/JetReco/interface/Jet.h"
0045 #include "DataFormats/Math/interface/deltaR.h"
0046
0047 #include "DataFormats/JetMatching/interface/JetFlavourInfoMatching.h"
0048
0049
0050
0051
0052
0053 class GenHFHadronMatcher : public edm::global::EDProducer<> {
0054 public:
0055 explicit GenHFHadronMatcher(const edm::ParameterSet &);
0056
0057 ~GenHFHadronMatcher() override = default;
0058
0059 static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
0060
0061 private:
0062 void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override;
0063
0064 std::vector<int> findHadronJets(const reco::GenParticleCollection *genParticles,
0065 const reco::JetFlavourInfoMatchingCollection *jetFlavourInfos,
0066 std::vector<int> &hadIndex,
0067 std::vector<reco::GenParticle> &hadMothersGenPart,
0068 std::vector<std::vector<int>> &hadMothersIndices,
0069 std::vector<int> &hadLeptonIndex,
0070 std::vector<int> &hadLeptonHadIndex,
0071 std::vector<int> &hadLeptonViaTau,
0072 std::vector<int> &hadFlavour,
0073 std::vector<int> &hadFromTopWeakDecay,
0074 std::vector<int> &hadBHadronId) const;
0075
0076 int analyzeMothers(const reco::Candidate *thisParticle,
0077 int &topDaughterQId,
0078 int &topBarDaughterQId,
0079 std::vector<const reco::Candidate *> &hadMothers,
0080 std::vector<std::vector<int>> &hadMothersIndices,
0081 std::set<const reco::Candidate *> &analyzedParticles,
0082 const int prevPartIndex) const;
0083 bool putMotherIndex(std::vector<std::vector<int>> &hadMothersIndices, int partIndex, int mothIndex) const;
0084 bool isHadron(const int flavour, const reco::Candidate *thisParticle) const;
0085 bool isHadronPdgId(const int flavour, const int pdgId) const;
0086 bool isMesonPdgId(const int flavour, const int pdgId) const;
0087 bool isBaryonPdgId(const int flavour, const int pdgId) const;
0088 int flavourSign(const int pdgId) const;
0089 bool hasHadronDaughter(const int flavour, const reco::Candidate *thisParticle) const;
0090 int idInList(std::vector<const reco::Candidate *> particleList, const reco::Candidate *particle) const;
0091 int idInList(std::vector<int> list, const int value) const;
0092 int findInMothers(int idx,
0093 std::vector<int> &mothChains,
0094 const std::vector<std::vector<int>> &hadMothersIndices,
0095 const std::vector<reco::GenParticle> &hadMothers,
0096 int status,
0097 int pdgId,
0098 bool pdgAbs,
0099 int stopId,
0100 int firstLast,
0101 bool verbose) const;
0102 bool isNeutralPdg(int pdgId) const;
0103
0104 bool checkForLoop(std::vector<const reco::Candidate *> &particleChain, const reco::Candidate *particle) const;
0105 std::string getParticleName(int id) const;
0106
0107 bool fixExtraSameFlavours(const unsigned int hadId,
0108 const std::vector<int> &hadIndices,
0109 const std::vector<reco::GenParticle> &hadMothers,
0110 const std::vector<std::vector<int>> &hadMothersIndices,
0111 const std::vector<int> &isFromTopWeakDecay,
0112 const std::vector<std::vector<int>> &LastQuarkIds,
0113 const std::vector<std::vector<int>> &LastQuarkMotherIds,
0114 std::vector<int> &lastQuarkIndices,
0115 std::vector<int> &hadronFlavour,
0116 std::set<int> &checkedHadronIds,
0117 const int lastQuarkIndex) const;
0118
0119
0120 const edm::EDGetTokenT<reco::GenParticleCollection> genParticlesToken_;
0121 const edm::EDGetTokenT<reco::JetFlavourInfoMatchingCollection> jetFlavourInfosToken_;
0122 const int flavour_;
0123 const bool noBBbarResonances_;
0124 const bool onlyJetClusteredHadrons_;
0125
0126 const std::string flavourStr_;
0127 const edm::EDPutTokenT<std::vector<reco::GenParticle>> plusMothersToken_;
0128 const edm::EDPutTokenT<std::vector<std::vector<int>>> plusMothersIndicesToken_;
0129 const edm::EDPutTokenT<std::vector<int>> indexToken_;
0130 const edm::EDPutTokenT<std::vector<int>> flavourToken_;
0131 const edm::EDPutTokenT<std::vector<int>> jetIndexToken_;
0132 const edm::EDPutTokenT<std::vector<int>> leptonIndexToken_;
0133 const edm::EDPutTokenT<std::vector<int>> leptonHadronIndexToken_;
0134 const edm::EDPutTokenT<std::vector<int>> leptonViaTauToken_;
0135 const edm::EDPutTokenT<std::vector<int>> fromTopWeakDecayToken_;
0136 const edm::EDPutTokenT<std::vector<int>> bHadronIdToken_;
0137 };
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 namespace {
0159 std::string flavourName(int flavour) {
0160 if (flavour == 5) {
0161 return "B";
0162 } else if (flavour == 4) {
0163 return "C";
0164 }
0165 edm::LogError("GenHFHadronMatcher") << "Flavour option must be 4 (c-jet) or 5 (b-jet), but is: " << flavour
0166 << ". Correct this!";
0167 return std::string();
0168 }
0169 }
0170
0171 GenHFHadronMatcher::GenHFHadronMatcher(const edm::ParameterSet &cfg)
0172 : genParticlesToken_(consumes<reco::GenParticleCollection>(cfg.getParameter<edm::InputTag>("genParticles"))),
0173 jetFlavourInfosToken_(
0174 consumes<reco::JetFlavourInfoMatchingCollection>(cfg.getParameter<edm::InputTag>("jetFlavourInfos"))),
0175 flavour_{std::abs(cfg.getParameter<int>("flavour"))},
0176 noBBbarResonances_{cfg.getParameter<bool>("noBBbarResonances")},
0177 onlyJetClusteredHadrons_{cfg.getParameter<bool>("onlyJetClusteredHadrons")},
0178 flavourStr_{flavourName(flavour_)},
0179 plusMothersToken_{produces<std::vector<reco::GenParticle>>(
0180 "gen" + flavourStr_ +
0181 "HadPlusMothers")},
0182 plusMothersIndicesToken_{produces<std::vector<std::vector<int>>>(
0183 "gen" + flavourStr_ + "HadPlusMothersIndices")},
0184 indexToken_{
0185 produces<std::vector<int>>("gen" + flavourStr_ + "HadIndex")},
0186 flavourToken_{produces<std::vector<int>>(
0187 "gen" + flavourStr_ +
0188 "HadFlavour")},
0189 jetIndexToken_{produces<std::vector<int>>(
0190 "gen" + flavourStr_ + "HadJetIndex")},
0191 leptonIndexToken_{produces<std::vector<int>>(
0192 "gen" + flavourStr_ +
0193 "HadLeptonIndex")},
0194 leptonHadronIndexToken_{produces<std::vector<int>>(
0195 "gen" + flavourStr_ + "HadLeptonHadronIndex")},
0196 leptonViaTauToken_{produces<std::vector<int>>(
0197 "gen" + flavourStr_ + "HadLeptonViaTau")},
0198 fromTopWeakDecayToken_{produces<std::vector<int>>(
0199 "gen" + flavourStr_ +
0200 "HadFromTopWeakDecay")},
0201 bHadronIdToken_{produces<std::vector<int>>("gen" + flavourStr_ + "HadBHadronId")}
0202
0203 {
0204
0205 }
0206
0207
0208
0209
0210
0211
0212 void GenHFHadronMatcher::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0213 edm::ParameterSetDescription desc;
0214 desc.add<edm::InputTag>("genParticles")
0215 ->setComment("Collection of GenParticle objects which contains all particles produced in the event");
0216 desc.add<edm::InputTag>("jetFlavourInfos")
0217 ->setComment(
0218 "Output from the JetFlavour tool. Contains information about partons/hadrons/leptons associated to jets");
0219 desc.add<bool>("noBBbarResonances", true)->setComment("Whether resonances should not be treated as hadrons");
0220 desc.add<bool>("onlyJetClusteredHadrons", false)
0221 ->setComment("Whether only hadrons that are matched to jets should be analysed. Runs x1000 faster in Sherpa");
0222 desc.add<int>("flavour", 5)->setComment("Flavour of weakly decaying hadron that should be analysed (4-c, 5-b)");
0223 descriptions.add("matchGenHFHadron", desc);
0224 }
0225
0226
0227
0228
0229
0230
0231 void GenHFHadronMatcher::produce(edm::StreamID, edm::Event &evt, const edm::EventSetup &setup) const {
0232 using namespace edm;
0233
0234 edm::Handle<reco::GenParticleCollection> genParticles;
0235 evt.getByToken(genParticlesToken_, genParticles);
0236
0237 edm::Handle<reco::JetFlavourInfoMatchingCollection> jetFlavourInfos;
0238 evt.getByToken(jetFlavourInfosToken_, jetFlavourInfos);
0239
0240
0241 std::vector<reco::GenParticle> hadMothers;
0242 std::vector<std::vector<int>> hadMothersIndices;
0243 std::vector<int> hadIndex;
0244 std::vector<int> hadFlavour;
0245 std::vector<int> hadJetIndex;
0246 std::vector<int> hadLeptonIndex;
0247 std::vector<int> hadLeptonHadIndex;
0248 std::vector<int> hadLeptonViaTau;
0249 std::vector<int> hadFromTopWeakDecay;
0250 std::vector<int> hadBHadronId;
0251
0252 hadJetIndex = findHadronJets(genParticles.product(),
0253 jetFlavourInfos.product(),
0254 hadIndex,
0255 hadMothers,
0256 hadMothersIndices,
0257 hadLeptonIndex,
0258 hadLeptonHadIndex,
0259 hadLeptonViaTau,
0260 hadFlavour,
0261 hadFromTopWeakDecay,
0262 hadBHadronId);
0263
0264
0265 evt.emplace(plusMothersToken_, std::move(hadMothers));
0266 evt.emplace(plusMothersIndicesToken_, std::move(hadMothersIndices));
0267 evt.emplace(indexToken_, std::move(hadIndex));
0268 evt.emplace(flavourToken_, std::move(hadFlavour));
0269 evt.emplace(jetIndexToken_, std::move(hadJetIndex));
0270 evt.emplace(leptonIndexToken_, std::move(hadLeptonIndex));
0271 evt.emplace(leptonHadronIndexToken_, std::move(hadLeptonHadIndex));
0272 evt.emplace(leptonViaTauToken_, std::move(hadLeptonViaTau));
0273 evt.emplace(fromTopWeakDecayToken_, std::move(hadFromTopWeakDecay));
0274 evt.emplace(bHadronIdToken_, std::move(hadBHadronId));
0275 }
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299 std::vector<int> GenHFHadronMatcher::findHadronJets(const reco::GenParticleCollection *genParticles,
0300 const reco::JetFlavourInfoMatchingCollection *jetFlavourInfos,
0301 std::vector<int> &hadIndex,
0302 std::vector<reco::GenParticle> &hadMothers,
0303 std::vector<std::vector<int>> &hadMothersIndices,
0304 std::vector<int> &hadLeptonIndex,
0305 std::vector<int> &hadLeptonHadIndex,
0306 std::vector<int> &hadLeptonViaTau,
0307 std::vector<int> &hadFlavour,
0308 std::vector<int> &hadFromTopWeakDecay,
0309 std::vector<int> &hadBHadronId) const {
0310 std::vector<int> hadJetIndex;
0311 std::vector<const reco::Candidate *> hadMothersCand;
0312
0313 int topDaughterQId = -1;
0314 int topBarDaughterQId = -1;
0315
0316
0317 for (reco::JetFlavourInfoMatchingCollection::const_iterator i_info = jetFlavourInfos->begin();
0318 i_info != jetFlavourInfos->end();
0319 ++i_info) {
0320 reco::JetFlavourInfo jetInfo = i_info->second;
0321 const int jetIndex = i_info - jetFlavourInfos->begin();
0322
0323 const reco::GenParticleRefVector &hadronsInJet = flavour_ == 5 ? jetInfo.getbHadrons()
0324 : flavour_ == 4 ? jetInfo.getcHadrons()
0325 : reco::GenParticleRefVector();
0326 for (reco::GenParticleRefVector::const_iterator hadron = hadronsInJet.begin(); hadron != hadronsInJet.end();
0327 ++hadron) {
0328
0329 if (!isHadron(flavour_, (&**hadron)))
0330 continue;
0331 if (hasHadronDaughter(flavour_, (reco::Candidate *)(&**hadron)))
0332 continue;
0333
0334 std::set<const reco::Candidate *> analyzedParticles;
0335 int hadronIndex = analyzeMothers((reco::Candidate *)(&**hadron),
0336 topDaughterQId,
0337 topBarDaughterQId,
0338 hadMothersCand,
0339 hadMothersIndices,
0340 analyzedParticles,
0341 -1);
0342
0343 hadIndex.push_back(hadronIndex);
0344 hadJetIndex.push_back(jetIndex);
0345 }
0346 }
0347
0348
0349 if (!onlyJetClusteredHadrons_) {
0350 for (reco::GenParticleCollection::const_iterator i_particle = genParticles->begin();
0351 i_particle != genParticles->end();
0352 ++i_particle) {
0353 const reco::GenParticle *thisParticle = &*i_particle;
0354 if (!isHadron(flavour_, thisParticle))
0355 continue;
0356
0357 if (std::find(hadMothersCand.begin(), hadMothersCand.end(), thisParticle) != hadMothersCand.end())
0358 continue;
0359
0360
0361 std::set<const reco::Candidate *> analyzedParticles;
0362 int hadronIndex = analyzeMothers(
0363 thisParticle, topDaughterQId, topBarDaughterQId, hadMothersCand, hadMothersIndices, analyzedParticles, -1);
0364
0365 hadIndex.push_back(hadronIndex);
0366 hadJetIndex.push_back(-1);
0367 }
0368 }
0369
0370
0371 for (int i = 0; i < (int)hadMothersCand.size(); i++) {
0372 const reco::GenParticle *particle = dynamic_cast<const reco::GenParticle *>(hadMothersCand.at(i));
0373 hadMothers.push_back(*particle);
0374 }
0375
0376
0377 for (reco::GenParticleCollection::const_iterator i_particle = genParticles->begin();
0378 i_particle != genParticles->end();
0379 ++i_particle) {
0380 const reco::GenParticle &lepton = *i_particle;
0381 const int pdg_abs = lepton.pdgId();
0382
0383 if (pdg_abs != 11 && pdg_abs != 13)
0384 continue;
0385 bool leptonViaTau = false;
0386 const reco::Candidate *leptonMother = lepton.mother();
0387 if (!leptonMother)
0388 continue;
0389
0390 if (std::abs(leptonMother->pdgId()) == 15) {
0391 leptonViaTau = true;
0392 leptonMother = leptonMother->mother();
0393 }
0394
0395 if (leptonMother == nullptr or !isHadron(flavour_, leptonMother))
0396 continue;
0397
0398 size_t leptonHadronParticleIndex =
0399 std::find(hadMothersCand.begin(), hadMothersCand.end(), leptonMother) - hadMothersCand.begin();
0400 if (leptonHadronParticleIndex >= hadMothersCand.size())
0401 continue;
0402
0403 size_t leptonHadronIndex =
0404 std::find(hadIndex.begin(), hadIndex.end(), leptonHadronParticleIndex) - hadIndex.begin();
0405 if (leptonHadronIndex >= hadIndex.size())
0406 continue;
0407
0408 hadMothers.push_back(lepton);
0409 const int leptonIndex = hadMothersCand.size() - 1;
0410 hadLeptonIndex.push_back(leptonIndex);
0411 hadLeptonViaTau.push_back(leptonViaTau);
0412 hadLeptonHadIndex.push_back(leptonHadronIndex);
0413 }
0414
0415
0416 unsigned int nHad = hadIndex.size();
0417
0418 std::vector<std::vector<int>> LastQuarkMotherIds;
0419 std::vector<std::vector<int>> LastQuarkIds;
0420 std::vector<int> lastQuarkIndices(nHad, -1);
0421
0422
0423 for (unsigned int hadNum = 0; hadNum < nHad; hadNum++) {
0424 unsigned int hadIdx = hadIndex.at(hadNum);
0425
0426 std::vector<int> FirstQuarkId;
0427 std::vector<int> LastQuarkId;
0428 std::vector<int> LastQuarkMotherId;
0429
0430 const int hadronFlavourSign = flavourSign(hadMothers.at(hadIdx).pdgId());
0431
0432
0433 if (hadronFlavourSign != 0) {
0434 findInMothers(
0435 hadIdx, FirstQuarkId, hadMothersIndices, hadMothers, 0, hadronFlavourSign * flavour_, false, -1, 1, false);
0436 }
0437
0438 else {
0439 findInMothers(hadIdx, FirstQuarkId, hadMothersIndices, hadMothers, 0, flavour_, false, -1, 1, false);
0440 findInMothers(hadIdx, FirstQuarkId, hadMothersIndices, hadMothers, 0, -1 * flavour_, false, -1, 1, false);
0441 }
0442
0443
0444 for (unsigned int qId = 0; qId < FirstQuarkId.size(); qId++) {
0445
0446 const int quarkFlavourSign = flavourSign(hadMothers.at(FirstQuarkId.at(qId)).pdgId());
0447
0448 findInMothers(FirstQuarkId.at(qId),
0449 LastQuarkId,
0450 hadMothersIndices,
0451 hadMothers,
0452 0,
0453 quarkFlavourSign * flavour_,
0454 false,
0455 -1,
0456 2,
0457 false);
0458 }
0459
0460
0461 int hadronFlavour = 0;
0462
0463
0464 std::vector<std::pair<double, int>> lastQuark_dR_id_pairs;
0465
0466
0467 for (unsigned int qId = 0; qId < LastQuarkId.size(); qId++) {
0468 int qIdx = LastQuarkId.at(qId);
0469
0470 float dR = deltaR(hadMothers.at(hadIdx).eta(),
0471 hadMothers.at(hadIdx).phi(),
0472 hadMothers.at(qIdx).eta(),
0473 hadMothers.at(qIdx).phi());
0474
0475 std::pair<double, int> dR_hadId_pair(dR, qIdx);
0476 lastQuark_dR_id_pairs.push_back(dR_hadId_pair);
0477 }
0478
0479 std::sort(lastQuark_dR_id_pairs.begin(), lastQuark_dR_id_pairs.end());
0480
0481 if (lastQuark_dR_id_pairs.size() > 1) {
0482 double dRratio =
0483 (lastQuark_dR_id_pairs.at(1).first - lastQuark_dR_id_pairs.at(0).first) / lastQuark_dR_id_pairs.at(1).first;
0484 int qIdx_closest = lastQuark_dR_id_pairs.at(0).second;
0485 LastQuarkId.clear();
0486 if (dRratio > 0.5)
0487 LastQuarkId.push_back(qIdx_closest);
0488 else
0489 for (std::pair<double, int> qIdDrPair : lastQuark_dR_id_pairs)
0490 LastQuarkId.push_back(qIdDrPair.second);
0491 }
0492 for (int qIdx : LastQuarkId) {
0493 int qmIdx = hadMothersIndices.at(qIdx).at(0);
0494 LastQuarkMotherId.push_back(qmIdx);
0495 }
0496
0497 if ((int)LastQuarkId.size() > 0)
0498 lastQuarkIndices.at(hadNum) = 0;
0499
0500 LastQuarkIds.push_back(LastQuarkId);
0501
0502 LastQuarkMotherIds.push_back(LastQuarkMotherId);
0503
0504 if (LastQuarkMotherId.empty()) {
0505 hadronFlavour = 0;
0506 } else {
0507 int qIdx = LastQuarkId.at(lastQuarkIndices.at(hadNum));
0508 int qFlav = flavourSign(hadMothers.at(qIdx).pdgId());
0509 hadronFlavour = qFlav * std::abs(hadMothers.at(LastQuarkMotherId.at(lastQuarkIndices.at(hadNum))).pdgId());
0510 }
0511 hadFlavour.push_back(hadronFlavour);
0512
0513
0514 int isFromTopWeakDecay = 1;
0515 std::vector<int> checkedParticles;
0516 if (hadFlavour.at(hadNum) != 0) {
0517 int lastQIndex = LastQuarkId.at(lastQuarkIndices.at(hadNum));
0518 bool fromTB = topDaughterQId >= 0 ? findInMothers(lastQIndex,
0519 checkedParticles,
0520 hadMothersIndices,
0521 hadMothers,
0522 -1,
0523 0,
0524 false,
0525 topDaughterQId,
0526 2,
0527 false) >= 0
0528 : false;
0529 checkedParticles.clear();
0530 bool fromTbarB = topBarDaughterQId >= 0 ? findInMothers(lastQIndex,
0531 checkedParticles,
0532 hadMothersIndices,
0533 hadMothers,
0534 -1,
0535 0,
0536 false,
0537 topBarDaughterQId,
0538 2,
0539 false) >= 0
0540 : false;
0541 checkedParticles.clear();
0542 if (!fromTB && !fromTbarB) {
0543 isFromTopWeakDecay = 0;
0544 }
0545 } else
0546 isFromTopWeakDecay = 2;
0547 hadFromTopWeakDecay.push_back(isFromTopWeakDecay);
0548 int bHadronMotherId =
0549 findInMothers(hadIdx, checkedParticles, hadMothersIndices, hadMothers, 0, 555555, true, -1, 1, false);
0550 hadBHadronId.push_back(bHadronMotherId);
0551
0552 if (!LastQuarkMotherId.empty()) {
0553 std::set<int> checkedHadronIds;
0554 fixExtraSameFlavours(hadNum,
0555 hadIndex,
0556 hadMothers,
0557 hadMothersIndices,
0558 hadFromTopWeakDecay,
0559 LastQuarkIds,
0560 LastQuarkMotherIds,
0561 lastQuarkIndices,
0562 hadFlavour,
0563 checkedHadronIds,
0564 0);
0565 }
0566
0567 }
0568
0569 return hadJetIndex;
0570 }
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580 int GenHFHadronMatcher::idInList(std::vector<const reco::Candidate *> particleList,
0581 const reco::Candidate *particle) const {
0582 const unsigned int position = std::find(particleList.begin(), particleList.end(), particle) - particleList.begin();
0583 if (position >= particleList.size())
0584 return -1;
0585
0586 return position;
0587 }
0588
0589 int GenHFHadronMatcher::idInList(std::vector<int> list, const int value) const {
0590 const unsigned int position = std::find(list.begin(), list.end(), value) - list.begin();
0591 if (position >= list.size())
0592 return -1;
0593
0594 return position;
0595 }
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605 bool GenHFHadronMatcher::isHadron(const int flavour, const reco::Candidate *thisParticle) const {
0606 return isHadronPdgId(flavour, thisParticle->pdgId());
0607 }
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617 bool GenHFHadronMatcher::isHadronPdgId(const int flavour, const int pdgId) const {
0618 if (isBaryonPdgId(flavour, pdgId) || isMesonPdgId(flavour, pdgId))
0619 return true;
0620
0621 return false;
0622 }
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632 bool GenHFHadronMatcher::isMesonPdgId(const int flavour, const int pdgId) const {
0633 const int flavour_abs = std::abs(flavour);
0634 if (flavour_abs != 5 && flavour_abs != 4)
0635 return false;
0636 const int pdgId_abs = std::abs(pdgId);
0637
0638 if (pdgId_abs / 100 % 10 != flavour_abs)
0639 return false;
0640
0641 if (pdgId_abs / 1000 == flavour_abs)
0642 return false;
0643
0644 if (noBBbarResonances_ && pdgId_abs / 10 % 100 == 11 * flavour_abs)
0645 return false;
0646
0647 return true;
0648 }
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658 bool GenHFHadronMatcher::isBaryonPdgId(const int flavour, const int pdgId) const {
0659 const int flavour_abs = std::abs(flavour);
0660 if (flavour_abs != 5 && flavour_abs != 4)
0661 return false;
0662 const int pdgId_abs = std::abs(pdgId);
0663
0664 if (pdgId_abs / 1000 != flavour_abs)
0665 return false;
0666
0667 return true;
0668 }
0669
0670
0671
0672
0673
0674
0675
0676
0677 int GenHFHadronMatcher::flavourSign(const int pdgId) const {
0678 int flavourSign = pdgId / std::abs(pdgId);
0679
0680 if (isMesonPdgId(5, pdgId))
0681 flavourSign *= -1;
0682
0683 if (pdgId % 1000 / 10 / 11 > 0)
0684 flavourSign = 0;
0685
0686 return flavourSign;
0687 }
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697 bool GenHFHadronMatcher::hasHadronDaughter(const int flavour, const reco::Candidate *thisParticle) const {
0698
0699 bool hasDaughter = false;
0700 for (int k = 0; k < (int)thisParticle->numberOfDaughters(); k++) {
0701 if (!isHadron(flavour, thisParticle->daughter(k))) {
0702 continue;
0703 }
0704 hasDaughter = true;
0705 break;
0706 }
0707
0708 return hasDaughter;
0709 }
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728 int GenHFHadronMatcher::analyzeMothers(const reco::Candidate *thisParticle,
0729 int &topDaughterQId,
0730 int &topBarDaughterQId,
0731 std::vector<const reco::Candidate *> &hadMothers,
0732 std::vector<std::vector<int>> &hadMothersIndices,
0733 std::set<const reco::Candidate *> &analyzedParticles,
0734 const int prevPartIndex) const {
0735
0736 int hadronIndex = -1;
0737 int index = idInList(hadMothers, thisParticle);
0738 if (index < 0) {
0739 hadMothers.push_back(thisParticle);
0740 hadronIndex = hadMothers.size() - 1;
0741 } else {
0742 hadronIndex = index;
0743 }
0744
0745 int partIndex = -1;
0746 partIndex = idInList(hadMothers, thisParticle);
0747
0748
0749 bool isLoop = false;
0750 for (unsigned int i = 0; i < analyzedParticles.size(); i++) {
0751 if (analyzedParticles.count(thisParticle) <= 0) {
0752 continue;
0753 }
0754 isLoop = true;
0755 break;
0756 }
0757
0758
0759 if (isLoop) {
0760 if (prevPartIndex >= 0) {
0761 putMotherIndex(hadMothersIndices, prevPartIndex, -1);
0762 }
0763 return hadronIndex;
0764 }
0765 analyzedParticles.insert(thisParticle);
0766
0767
0768 for (size_t iMother = 0; iMother < thisParticle->numberOfMothers(); ++iMother) {
0769 const reco::Candidate *mother = thisParticle->mother(iMother);
0770 int mothIndex = idInList(hadMothers, mother);
0771 if (mothIndex == partIndex && partIndex >= 0) {
0772 continue;
0773 }
0774
0775
0776 if (mothIndex < 0) {
0777 hadMothers.push_back(mother);
0778 mothIndex = hadMothers.size() - 1;
0779 }
0780
0781 if (mothIndex != partIndex && partIndex >= 0) {
0782 putMotherIndex(hadMothersIndices, partIndex, mothIndex);
0783 }
0784 analyzeMothers(
0785 mother, topDaughterQId, topBarDaughterQId, hadMothers, hadMothersIndices, analyzedParticles, partIndex);
0786
0787 if (std::abs(mother->pdgId()) == 6) {
0788 int &bId = mother->pdgId() < 0 ? topBarDaughterQId : topDaughterQId;
0789 int thisFlav = std::abs(thisParticle->pdgId());
0790 if (bId < 0) {
0791 if (thisFlav <= 5)
0792 bId = partIndex;
0793 } else {
0794 int bIdFlav = std::abs(hadMothers.at(bId)->pdgId());
0795 if (bIdFlav != 5 && thisFlav == 5)
0796 bId = partIndex;
0797 else if (thisFlav == 5 && thisParticle->pt() > hadMothers.at(bId)->pt())
0798 bId = partIndex;
0799 }
0800 }
0801 }
0802
0803 analyzedParticles.erase(thisParticle);
0804
0805 if (partIndex < 0) {
0806 return hadronIndex;
0807 }
0808
0809
0810 if ((int)thisParticle->numberOfMothers() <= 0) {
0811 putMotherIndex(hadMothersIndices, partIndex, -1);
0812 }
0813
0814 return hadronIndex;
0815 }
0816
0817
0818
0819
0820
0821
0822
0823
0824
0825
0826 bool GenHFHadronMatcher::putMotherIndex(std::vector<std::vector<int>> &hadMothersIndices,
0827 int partIndex,
0828 int mothIndex) const {
0829
0830 bool inList = false;
0831 if (partIndex < 0) {
0832 return false;
0833 }
0834
0835 while ((int)hadMothersIndices.size() <= partIndex) {
0836 std::vector<int> mothersIndices;
0837 hadMothersIndices.push_back(mothersIndices);
0838 }
0839
0840 std::vector<int> *hadMotherIndices = &hadMothersIndices.at(partIndex);
0841
0842 if (mothIndex == -1) {
0843 hadMotherIndices->clear();
0844 } else {
0845
0846 for (int k = 0; k < (int)hadMotherIndices->size(); k++) {
0847 if (hadMotherIndices->at(k) != mothIndex && hadMotherIndices->at(k) != -1) {
0848 continue;
0849 }
0850 inList = true;
0851 break;
0852 }
0853 }
0854
0855 if (!inList) {
0856 hadMotherIndices->push_back(mothIndex);
0857 }
0858
0859 return inList;
0860 }
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873
0874
0875
0876
0877
0878
0879 int GenHFHadronMatcher::findInMothers(int idx,
0880 std::vector<int> &mothChains,
0881 const std::vector<std::vector<int>> &hadMothersIndices,
0882 const std::vector<reco::GenParticle> &hadMothers,
0883 int status,
0884 int pdgId,
0885 bool pdgAbs = false,
0886 int stopId = -1,
0887 int firstLast = 0,
0888 bool verbose = false) const {
0889 int foundStopId = -1;
0890 int pdg_1 = hadMothers.at(idx).pdgId();
0891
0892 if ((int)hadMothersIndices.size() <= idx) {
0893 if (verbose) {
0894 printf(" Stopping checking particle %d. No mothers are stored.\n", idx);
0895 }
0896 return -1;
0897 }
0898
0899 if (std::abs(hadMothers.at(idx).pdgId()) > 10 && std::abs(hadMothers.at(idx).pdgId()) < 19)
0900 printf("Lepton: %d\n", hadMothers.at(idx).pdgId());
0901
0902 std::vector<int> mothers = hadMothersIndices.at(idx);
0903 unsigned int nMothers = mothers.size();
0904 bool isCorrect = false;
0905 if (verbose) {
0906 if (std::abs(hadMothers.at(idx).pdgId()) == 2212) {
0907 printf("Chk: %d\tpdg: %d\tstatus: %d", idx, hadMothers.at(idx).pdgId(), hadMothers.at(idx).status());
0908 } else {
0909 printf(" Chk: %d(%d mothers)\tpdg: %d\tstatus: %d\tPt: %.3f\tEta: %.3f",
0910 idx,
0911 nMothers,
0912 hadMothers.at(idx).pdgId(),
0913 hadMothers.at(idx).status(),
0914 hadMothers.at(idx).pt(),
0915 hadMothers.at(idx).eta());
0916 }
0917 }
0918 bool hasCorrectMothers = true;
0919 if (nMothers < 1)
0920 hasCorrectMothers = false;
0921 else if (mothers.at(0) < 0)
0922 hasCorrectMothers = false;
0923 if (!hasCorrectMothers) {
0924 if (verbose)
0925 printf(" NO CORRECT MOTHER\n");
0926 return -1;
0927 }
0928
0929 if (stopId >= 0 && idx == stopId)
0930 return idx;
0931
0932
0933 if (pdgId % 111111 == 0 && pdgId != 0) {
0934 if (isHadronPdgId(pdgId / 111111, hadMothers.at(idx).pdgId())) {
0935 return idx;
0936 }
0937 }
0938
0939
0940 if (((hadMothers.at(idx).pdgId() == pdgId && pdgAbs == false) ||
0941 (std::abs(hadMothers.at(idx).pdgId()) == std::abs(pdgId) && pdgAbs == true)) &&
0942 (hadMothers.at(idx).status() == status || status == 0) && hasCorrectMothers) {
0943 isCorrect = true;
0944
0945 const bool inList = std::find(mothChains.begin(), mothChains.end(), idx) != mothChains.end();
0946 if (!inList && mothers.at(0) >= 0 && (hadMothers.at(idx).pdgId() * pdgId > 0 || !pdgAbs)) {
0947 if (firstLast == 0 || firstLast == 1) {
0948 mothChains.push_back(idx);
0949 }
0950 if (verbose) {
0951 printf(" *");
0952 }
0953 }
0954 if (verbose) {
0955 printf(" +++");
0956 }
0957 }
0958 if (verbose) {
0959 printf("\n");
0960 }
0961
0962 if (isCorrect && firstLast == 1) {
0963 return -1;
0964 }
0965
0966
0967 unsigned int nDifferingMothers = 0;
0968 for (unsigned int i = 0; i < nMothers; i++) {
0969 int idx2 = mothers.at(i);
0970 if (idx2 < 0) {
0971 if (verbose)
0972 printf("^^^ Has no mother\n");
0973 continue;
0974 }
0975 if (idx2 == idx) {
0976 if (verbose)
0977 printf("^^^ Stored as its own mother\n");
0978 continue;
0979 }
0980 int pdg_2 = hadMothers[idx2].pdgId();
0981
0982 if (isHadronPdgId(pdgId, pdg_1) && isHadronPdgId(pdgId, pdg_2) && pdg_1 * pdg_2 < 0) {
0983 pdgId *= -1;
0984 if (verbose)
0985 printf("######### Inverting flavour of the hadron\n");
0986 }
0987
0988 if ((std::abs(pdg_2) != std::abs(pdgId) && pdgAbs == true) || (pdg_2 != pdgId && pdgAbs == false)) {
0989 nDifferingMothers++;
0990 }
0991
0992
0993 if (verbose) {
0994 printf("Checking mother %d out of %d mothers (%d -> %d), looking for pdgId: %d\n", i, nMothers, idx, idx2, pdgId);
0995 }
0996 if (firstLast == 2 && pdg_1 != pdg_2)
0997 continue;
0998 foundStopId = findInMothers(
0999 idx2, mothChains, hadMothersIndices, hadMothers, status, pdgId, pdgAbs, stopId, firstLast, verbose);
1000 }
1001
1002 if (firstLast == 2 && isCorrect && nDifferingMothers >= nMothers) {
1003 if (verbose) {
1004 printf("Checking particle %d once more to store it as the last quark\n", idx);
1005 }
1006 foundStopId = findInMothers(idx, mothChains, hadMothersIndices, hadMothers, 0, pdgId, pdgAbs, stopId, 1, verbose);
1007 }
1008
1009 return foundStopId;
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 bool GenHFHadronMatcher::isNeutralPdg(int pdgId) const {
1021 const int neutralPdgs_array[] = {9, 21, 22, 23, 25};
1022 const std::vector<int> neutralPdgs(neutralPdgs_array, neutralPdgs_array + sizeof(neutralPdgs_array) / sizeof(int));
1023 if (std::find(neutralPdgs.begin(), neutralPdgs.end(), std::abs(pdgId)) == neutralPdgs.end())
1024 return false;
1025
1026 return true;
1027 }
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043 bool GenHFHadronMatcher::fixExtraSameFlavours(const unsigned int hadId,
1044 const std::vector<int> &hadIndices,
1045 const std::vector<reco::GenParticle> &hadMothers,
1046 const std::vector<std::vector<int>> &hadMothersIndices,
1047 const std::vector<int> &isFromTopWeakDecay,
1048 const std::vector<std::vector<int>> &LastQuarkIds,
1049 const std::vector<std::vector<int>> &LastQuarkMotherIds,
1050 std::vector<int> &lastQuarkIndices,
1051 std::vector<int> &hadronFlavour,
1052 std::set<int> &checkedHadronIds,
1053 const int lastQuarkIndex) const {
1054 if (checkedHadronIds.count(hadId) != 0)
1055 return false;
1056 checkedHadronIds.insert(hadId);
1057
1058 if (lastQuarkIndex < 0)
1059 return false;
1060 if ((int)LastQuarkIds.at(hadId).size() < lastQuarkIndex + 1)
1061 return false;
1062 int LastQuarkId = LastQuarkIds.at(hadId).at(lastQuarkIndex);
1063 int LastQuarkMotherId = LastQuarkMotherIds.at(hadId).at(lastQuarkIndex);
1064 int qmFlav = hadMothers.at(LastQuarkId).pdgId() < 0 ? -1 : 1;
1065 int hadFlavour = qmFlav * std::abs(hadMothers.at(LastQuarkMotherId).pdgId());
1066 bool ambiguityResolved = true;
1067
1068 if ((hadMothers.at(LastQuarkId).pdgId() * hadMothers.at(LastQuarkMotherId).pdgId() < 0 &&
1069 !isNeutralPdg(hadMothers.at(LastQuarkMotherId).pdgId())) ||
1070
1071 (std::abs(hadronFlavour.at(hadId)) == 6 && isFromTopWeakDecay.at(hadId) == 0)) {
1072 if ((int)LastQuarkIds.at(hadId).size() > lastQuarkIndex + 1)
1073 fixExtraSameFlavours(hadId,
1074 hadIndices,
1075 hadMothers,
1076 hadMothersIndices,
1077 isFromTopWeakDecay,
1078 LastQuarkIds,
1079 LastQuarkMotherIds,
1080 lastQuarkIndices,
1081 hadronFlavour,
1082 checkedHadronIds,
1083 lastQuarkIndex + 1);
1084 else
1085 hadronFlavour.at(hadId) = qmFlav * 21;
1086 return true;
1087 }
1088
1089 int nSameFlavourHadrons = 0;
1090
1091 for (unsigned int iHad = 0; iHad < hadronFlavour.size(); iHad++) {
1092 if (iHad == hadId)
1093 continue;
1094 int theLastQuarkIndex = lastQuarkIndices.at(iHad);
1095 if (theLastQuarkIndex < 0)
1096 continue;
1097 if ((int)LastQuarkMotherIds.at(iHad).size() <= theLastQuarkIndex)
1098 continue;
1099 int theLastQuarkMotherId = LastQuarkMotherIds.at(iHad).at(theLastQuarkIndex);
1100 int theHadFlavour = hadronFlavour.at(iHad);
1101
1102 if (theHadFlavour == 0 || std::abs(theHadFlavour) == 21)
1103 continue;
1104 if (theHadFlavour != hadFlavour || theLastQuarkMotherId != LastQuarkMotherId)
1105 continue;
1106 ambiguityResolved = false;
1107 nSameFlavourHadrons++;
1108
1109
1110 if ((int)LastQuarkIds.at(hadId).size() > lastQuarkIndex + 1) {
1111 if (fixExtraSameFlavours(hadId,
1112 hadIndices,
1113 hadMothers,
1114 hadMothersIndices,
1115 isFromTopWeakDecay,
1116 LastQuarkIds,
1117 LastQuarkMotherIds,
1118 lastQuarkIndices,
1119 hadronFlavour,
1120 checkedHadronIds,
1121 lastQuarkIndex + 1)) {
1122 ambiguityResolved = true;
1123 break;
1124 }
1125 } else
1126
1127 if ((int)LastQuarkIds.at(iHad).size() > theLastQuarkIndex + 1) {
1128 if (fixExtraSameFlavours(iHad,
1129 hadIndices,
1130 hadMothers,
1131 hadMothersIndices,
1132 isFromTopWeakDecay,
1133 LastQuarkIds,
1134 LastQuarkMotherIds,
1135 lastQuarkIndices,
1136 hadronFlavour,
1137 checkedHadronIds,
1138 theLastQuarkIndex + 1)) {
1139 ambiguityResolved = true;
1140 break;
1141 };
1142 }
1143
1144 }
1145
1146 checkedHadronIds.erase(hadId);
1147 if (nSameFlavourHadrons > 0 && !ambiguityResolved) {
1148 hadronFlavour.at(hadId) = qmFlav * 21;
1149 return true;
1150 }
1151 lastQuarkIndices.at(hadId) = lastQuarkIndex;
1152 hadronFlavour.at(hadId) = hadFlavour;
1153 return true;
1154 }
1155
1156
1157 DEFINE_FWK_MODULE(GenHFHadronMatcher);