File indexing completed on 2024-04-06 12:23:33
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 #include <memory>
0080
0081
0082 #include "FWCore/Framework/interface/Frameworkfwd.h"
0083 #include "FWCore/Framework/interface/stream/EDProducer.h"
0084
0085 #include "FWCore/Framework/interface/Event.h"
0086 #include "FWCore/Framework/interface/MakerMacros.h"
0087
0088 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0089
0090 #include "DataFormats/JetReco/interface/Jet.h"
0091 #include "DataFormats/JetReco/interface/JetCollection.h"
0092 #include "DataFormats/JetMatching/interface/JetFlavourInfo.h"
0093 #include "DataFormats/JetMatching/interface/JetFlavourInfoMatching.h"
0094 #include "DataFormats/HepMCCandidate/interface/GenParticle.h"
0095 #include "DataFormats/HepMCCandidate/interface/GenParticleFwd.h"
0096 #include "DataFormats/Math/interface/deltaR.h"
0097 #include "PhysicsTools/JetMCUtils/interface/CandMCTag.h"
0098 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
0099
0100 #include "fastjet/JetDefinition.hh"
0101 #include "fastjet/ClusterSequence.hh"
0102 #include "fastjet/Selector.hh"
0103 #include "fastjet/PseudoJet.hh"
0104
0105
0106
0107
0108 typedef std::shared_ptr<fastjet::ClusterSequence> ClusterSequencePtr;
0109 typedef std::shared_ptr<fastjet::JetDefinition> JetDefPtr;
0110
0111
0112
0113
0114 class GhostInfo : public fastjet::PseudoJet::UserInfoBase {
0115 public:
0116 GhostInfo(const bool& isHadron,
0117 const bool& isbHadron,
0118 const bool& isParton,
0119 const bool& isLepton,
0120 const reco::GenParticleRef& particleRef)
0121 : m_particleRef(particleRef) {
0122 m_type = 0;
0123 if (isHadron)
0124 m_type |= (1 << 0);
0125 if (isbHadron)
0126 m_type |= (1 << 1);
0127 if (isParton)
0128 m_type |= (1 << 2);
0129 if (isLepton)
0130 m_type |= (1 << 3);
0131 }
0132
0133 const bool isHadron() const { return (m_type & (1 << 0)); }
0134 const bool isbHadron() const { return (m_type & (1 << 1)); }
0135 const bool isParton() const { return (m_type & (1 << 2)); }
0136 const bool isLepton() const { return (m_type & (1 << 3)); }
0137 const reco::GenParticleRef& particleRef() const { return m_particleRef; }
0138
0139 protected:
0140 const reco::GenParticleRef m_particleRef;
0141 int m_type;
0142 };
0143
0144 class JetFlavourClustering : public edm::stream::EDProducer<> {
0145 public:
0146 explicit JetFlavourClustering(const edm::ParameterSet&);
0147 ~JetFlavourClustering() override;
0148
0149 static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0150
0151 private:
0152 void produce(edm::Event&, const edm::EventSetup&) override;
0153
0154 void insertGhosts(const edm::Handle<reco::GenParticleRefVector>& particles,
0155 const double ghostRescaling,
0156 const bool isHadron,
0157 const bool isbHadron,
0158 const bool isParton,
0159 const bool isLepton,
0160 std::vector<fastjet::PseudoJet>& constituents);
0161
0162 void matchReclusteredJets(const edm::Handle<edm::View<reco::Jet>>& jets,
0163 const std::vector<fastjet::PseudoJet>& matchedJets,
0164 std::vector<int>& matchedIndices);
0165 void matchGroomedJets(const edm::Handle<edm::View<reco::Jet>>& jets,
0166 const edm::Handle<edm::View<reco::Jet>>& matchedJets,
0167 std::vector<int>& matchedIndices);
0168 void matchSubjets(const std::vector<int>& groomedIndices,
0169 const edm::Handle<edm::View<reco::Jet>>& groomedJets,
0170 const edm::Handle<edm::View<reco::Jet>>& subjets,
0171 std::vector<std::vector<int>>& matchedIndices);
0172
0173 void setFlavours(const reco::GenParticleRefVector& clusteredbHadrons,
0174 const reco::GenParticleRefVector& clusteredcHadrons,
0175 const reco::GenParticleRefVector& clusteredPartons,
0176 int& hadronFlavour,
0177 int& partonFlavour);
0178
0179 void assignToSubjets(const reco::GenParticleRefVector& clusteredParticles,
0180 const edm::Handle<edm::View<reco::Jet>>& subjets,
0181 const std::vector<int>& subjetIndices,
0182 std::vector<reco::GenParticleRefVector>& assignedParticles);
0183
0184
0185 const edm::EDGetTokenT<edm::View<reco::Jet>> jetsToken_;
0186 edm::EDGetTokenT<edm::View<reco::Jet>> groomedJetsToken_;
0187 edm::EDGetTokenT<edm::View<reco::Jet>> subjetsToken_;
0188 const edm::EDGetTokenT<reco::GenParticleRefVector> bHadronsToken_;
0189 const edm::EDGetTokenT<reco::GenParticleRefVector> cHadronsToken_;
0190 const edm::EDGetTokenT<reco::GenParticleRefVector> partonsToken_;
0191 edm::EDGetTokenT<edm::ValueMap<float>> weightsToken_;
0192 edm::EDGetTokenT<reco::GenParticleRefVector> leptonsToken_;
0193
0194 const std::string jetAlgorithm_;
0195 const double rParam_;
0196 const double jetPtMin_;
0197 const double ghostRescaling_;
0198 const double relPtTolerance_;
0199 const bool hadronFlavourHasPriority_;
0200 const bool useSubjets_;
0201
0202 const bool useLeptons_;
0203
0204 ClusterSequencePtr fjClusterSeq_;
0205 JetDefPtr fjJetDefinition_;
0206 };
0207
0208
0209
0210
0211
0212
0213
0214
0215 JetFlavourClustering::JetFlavourClustering(const edm::ParameterSet& iConfig)
0216 : jetsToken_(consumes<edm::View<reco::Jet>>(iConfig.getParameter<edm::InputTag>("jets"))),
0217 bHadronsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("bHadrons"))),
0218 cHadronsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("cHadrons"))),
0219 partonsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("partons"))),
0220 jetAlgorithm_(iConfig.getParameter<std::string>("jetAlgorithm")),
0221 rParam_(iConfig.getParameter<double>("rParam")),
0222
0223 jetPtMin_(
0224 0.),
0225 ghostRescaling_(iConfig.exists("ghostRescaling") ? iConfig.getParameter<double>("ghostRescaling") : 1e-18),
0226 relPtTolerance_(
0227 iConfig.exists("relPtTolerance")
0228 ? iConfig.getParameter<double>("relPtTolerance")
0229 : 1e-03),
0230 hadronFlavourHasPriority_(iConfig.getParameter<bool>("hadronFlavourHasPriority")),
0231 useSubjets_(iConfig.exists("groomedJets") && iConfig.exists("subjets")),
0232 useLeptons_(iConfig.exists("leptons"))
0233
0234 {
0235
0236 produces<reco::JetFlavourInfoMatchingCollection>();
0237 if (iConfig.existsAs<edm::InputTag>("weights"))
0238 weightsToken_ = consumes<edm::ValueMap<float>>(iConfig.getParameter<edm::InputTag>("weights"));
0239
0240 if (useSubjets_)
0241 produces<reco::JetFlavourInfoMatchingCollection>("SubJets");
0242
0243
0244 if (jetAlgorithm_ == "Kt")
0245 fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::kt_algorithm, rParam_);
0246 else if (jetAlgorithm_ == "CambridgeAachen")
0247 fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::cambridge_algorithm, rParam_);
0248 else if (jetAlgorithm_ == "AntiKt")
0249 fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::antikt_algorithm, rParam_);
0250 else
0251 throw cms::Exception("InvalidJetAlgorithm") << "Jet clustering algorithm is invalid: " << jetAlgorithm_
0252 << ", use CambridgeAachen | Kt | AntiKt" << std::endl;
0253
0254 if (useSubjets_) {
0255 groomedJetsToken_ = consumes<edm::View<reco::Jet>>(iConfig.getParameter<edm::InputTag>("groomedJets"));
0256 subjetsToken_ = consumes<edm::View<reco::Jet>>(iConfig.getParameter<edm::InputTag>("subjets"));
0257 }
0258 if (useLeptons_) {
0259 leptonsToken_ = consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("leptons"));
0260 }
0261 }
0262
0263 JetFlavourClustering::~JetFlavourClustering() {
0264
0265
0266 }
0267
0268
0269
0270
0271
0272
0273 void JetFlavourClustering::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0274 edm::Handle<edm::View<reco::Jet>> jets;
0275 iEvent.getByToken(jetsToken_, jets);
0276
0277 edm::Handle<edm::View<reco::Jet>> groomedJets;
0278 edm::Handle<edm::View<reco::Jet>> subjets;
0279 if (useSubjets_) {
0280 iEvent.getByToken(groomedJetsToken_, groomedJets);
0281 iEvent.getByToken(subjetsToken_, subjets);
0282 }
0283
0284 edm::Handle<reco::GenParticleRefVector> bHadrons;
0285 iEvent.getByToken(bHadronsToken_, bHadrons);
0286
0287 edm::Handle<reco::GenParticleRefVector> cHadrons;
0288 iEvent.getByToken(cHadronsToken_, cHadrons);
0289
0290 edm::Handle<reco::GenParticleRefVector> partons;
0291 iEvent.getByToken(partonsToken_, partons);
0292
0293 edm::Handle<edm::ValueMap<float>> weights;
0294 if (!weightsToken_.isUninitialized())
0295 iEvent.getByToken(weightsToken_, weights);
0296
0297 edm::Handle<reco::GenParticleRefVector> leptons;
0298 if (useLeptons_)
0299 iEvent.getByToken(leptonsToken_, leptons);
0300
0301 auto jetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(reco::JetRefBaseProd(jets));
0302 std::unique_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
0303 if (useSubjets_)
0304 subjetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(reco::JetRefBaseProd(subjets));
0305
0306
0307 std::vector<fastjet::PseudoJet> fjInputs;
0308 unsigned int reserve = jets->size() * 128 + bHadrons->size() + cHadrons->size() + partons->size();
0309 if (useLeptons_)
0310 reserve += leptons->size();
0311 fjInputs.reserve(reserve);
0312
0313 for (edm::View<reco::Jet>::const_iterator it = jets->begin(); it != jets->end(); ++it) {
0314 std::vector<edm::Ptr<reco::Candidate>> constituents = it->getJetConstituents();
0315 std::vector<edm::Ptr<reco::Candidate>>::const_iterator m;
0316 for (m = constituents.begin(); m != constituents.end(); ++m) {
0317 const reco::CandidatePtr& constit = *m;
0318 if (!constit.isNonnull() || !constit.isAvailable()) {
0319 edm::LogError("MissingJetConstituent") << "Jet constituent required for jet reclustering is missing. "
0320 "Reclustered jets are not guaranteed to reproduce the original jets!";
0321 continue;
0322 }
0323 if (constit->pt() == 0) {
0324 edm::LogWarning("NullTransverseMomentum") << "dropping input candidate with pt=0";
0325 continue;
0326 }
0327 if (it->isWeighted()) {
0328 if (weightsToken_.isUninitialized())
0329 throw cms::Exception("MissingConstituentWeight")
0330 << "JetFlavourClustering: No weights (e.g. PUPPI) given for weighted jet collection" << std::endl;
0331 float w = (*weights)[constit];
0332 fjInputs.push_back(
0333 fastjet::PseudoJet(constit->px() * w, constit->py() * w, constit->pz() * w, constit->energy() * w));
0334 } else {
0335 fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
0336 }
0337 }
0338 }
0339
0340 insertGhosts(bHadrons, ghostRescaling_, true, true, false, false, fjInputs);
0341
0342 insertGhosts(cHadrons, ghostRescaling_, true, false, false, false, fjInputs);
0343
0344 insertGhosts(partons, ghostRescaling_, false, false, true, false, fjInputs);
0345
0346 if (useLeptons_)
0347 insertGhosts(leptons, ghostRescaling_, false, false, false, true, fjInputs);
0348
0349
0350 fjClusterSeq_ = std::make_shared<fastjet::ClusterSequence>(fjInputs, *fjJetDefinition_);
0351
0352 std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(fjClusterSeq_->inclusive_jets(jetPtMin_));
0353
0354 if (inclusiveJets.size() < jets->size())
0355 edm::LogError("TooFewReclusteredJets")
0356 << "There are fewer reclustered (" << inclusiveJets.size() << ") than original jets (" << jets->size()
0357 << "). Please check that the jet algorithm and jet size match those used for the original jet collection.";
0358
0359
0360 std::vector<int> reclusteredIndices;
0361 matchReclusteredJets(jets, inclusiveJets, reclusteredIndices);
0362
0363
0364 std::vector<int> groomedIndices;
0365 if (useSubjets_) {
0366 if (groomedJets->size() > jets->size())
0367 edm::LogError("TooManyGroomedJets")
0368 << "There are more groomed (" << groomedJets->size() << ") than original jets (" << jets->size()
0369 << "). Please check that the two jet collections belong to each other.";
0370
0371 matchGroomedJets(jets, groomedJets, groomedIndices);
0372 }
0373
0374
0375 std::vector<std::vector<int>> subjetIndices;
0376 if (useSubjets_) {
0377 matchSubjets(groomedIndices, groomedJets, subjets, subjetIndices);
0378 }
0379
0380
0381 for (size_t i = 0; i < jets->size(); ++i) {
0382 reco::GenParticleRefVector clusteredbHadrons;
0383 reco::GenParticleRefVector clusteredcHadrons;
0384 reco::GenParticleRefVector clusteredPartons;
0385 reco::GenParticleRefVector clusteredLeptons;
0386
0387
0388 if (reclusteredIndices.at(i) < 0) {
0389
0390 (*jetFlavourInfos)[jets->refAt(i)] =
0391 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
0392 } else if (jets->at(i).pt() == 0) {
0393 edm::LogWarning("NullTransverseMomentum")
0394 << "The original jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
0395
0396
0397 (*jetFlavourInfos)[jets->refAt(i)] =
0398 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
0399
0400
0401 if (useSubjets_ && !subjetIndices.at(i).empty()) {
0402
0403 for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj) {
0404
0405 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] =
0406 reco::JetFlavourInfo(reco::GenParticleRefVector(),
0407 reco::GenParticleRefVector(),
0408 reco::GenParticleRefVector(),
0409 reco::GenParticleRefVector(),
0410 0,
0411 0);
0412 }
0413 }
0414 } else {
0415
0416 if ((std::abs(inclusiveJets.at(reclusteredIndices.at(i)).pt() - jets->at(i).pt()) / jets->at(i).pt()) >
0417 relPtTolerance_) {
0418 if (jets->at(i).pt() < 10.)
0419 edm::LogWarning("JetPtMismatchAtLowPt")
0420 << "The reclustered and original jet " << i << " have different Pt's ("
0421 << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << jets->at(i).pt()
0422 << " GeV, respectively).\n"
0423 << "Please check that the jet algorithm and jet size match those used for the original jet collection "
0424 "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
0425 "CaloJets which are presently not supported.\n"
0426 << "Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n"
0427 << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision "
0428 "in which case make sure the original jet collection is produced and reclustering is performed in the "
0429 "same job.";
0430 else
0431 edm::LogError("JetPtMismatch")
0432 << "The reclustered and original jet " << i << " have different Pt's ("
0433 << inclusiveJets.at(reclusteredIndices.at(i)).pt() << " vs " << jets->at(i).pt()
0434 << " GeV, respectively).\n"
0435 << "Please check that the jet algorithm and jet size match those used for the original jet collection "
0436 "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
0437 "CaloJets which are presently not supported.\n"
0438 << "\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision "
0439 "in which case make sure the original jet collection is produced and reclustering is performed in the "
0440 "same job.";
0441 }
0442
0443
0444 std::vector<fastjet::PseudoJet> constituents =
0445 fastjet::sorted_by_pt(inclusiveJets.at(reclusteredIndices.at(i)).constituents());
0446
0447
0448 for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it) {
0449 if (!it->has_user_info())
0450 continue;
0451
0452
0453 if (it->user_info<GhostInfo>().isHadron()) {
0454
0455 if (it->user_info<GhostInfo>().isbHadron())
0456 clusteredbHadrons.push_back(it->user_info<GhostInfo>().particleRef());
0457
0458 else
0459 clusteredcHadrons.push_back(it->user_info<GhostInfo>().particleRef());
0460 }
0461
0462 else if (it->user_info<GhostInfo>().isParton())
0463 clusteredPartons.push_back(it->user_info<GhostInfo>().particleRef());
0464
0465 else if (it->user_info<GhostInfo>().isLepton())
0466 clusteredLeptons.push_back(it->user_info<GhostInfo>().particleRef());
0467 }
0468
0469 int hadronFlavour = 0;
0470 int partonFlavour = 0;
0471
0472
0473 setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
0474
0475
0476 (*jetFlavourInfos)[jets->refAt(i)] = reco::JetFlavourInfo(
0477 clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
0478 }
0479
0480
0481 if (useSubjets_) {
0482 if (subjetIndices.at(i).empty())
0483 continue;
0484
0485
0486 std::vector<reco::GenParticleRefVector> assignedbHadrons(subjetIndices.at(i).size(),
0487 reco::GenParticleRefVector());
0488 std::vector<reco::GenParticleRefVector> assignedcHadrons(subjetIndices.at(i).size(),
0489 reco::GenParticleRefVector());
0490 std::vector<reco::GenParticleRefVector> assignedPartons(subjetIndices.at(i).size(), reco::GenParticleRefVector());
0491 std::vector<reco::GenParticleRefVector> assignedLeptons(subjetIndices.at(i).size(), reco::GenParticleRefVector());
0492
0493
0494 assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(i), assignedbHadrons);
0495
0496 assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(i), assignedcHadrons);
0497
0498 assignToSubjets(clusteredPartons, subjets, subjetIndices.at(i), assignedPartons);
0499
0500 if (useLeptons_)
0501 assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(i), assignedLeptons);
0502
0503
0504 for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj) {
0505 int subjetHadronFlavour = 0;
0506 int subjetPartonFlavour = 0;
0507
0508
0509 setFlavours(assignedbHadrons.at(sj),
0510 assignedcHadrons.at(sj),
0511 assignedPartons.at(sj),
0512 subjetHadronFlavour,
0513 subjetPartonFlavour);
0514
0515
0516 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] =
0517 reco::JetFlavourInfo(assignedbHadrons.at(sj),
0518 assignedcHadrons.at(sj),
0519 assignedPartons.at(sj),
0520 assignedLeptons.at(sj),
0521 subjetHadronFlavour,
0522 subjetPartonFlavour);
0523 }
0524 }
0525 }
0526
0527
0528 fjClusterSeq_.reset();
0529
0530
0531 iEvent.put(std::move(jetFlavourInfos));
0532
0533 if (useSubjets_)
0534 iEvent.put(std::move(subjetFlavourInfos), "SubJets");
0535 }
0536
0537
0538 void JetFlavourClustering::insertGhosts(const edm::Handle<reco::GenParticleRefVector>& particles,
0539 const double ghostRescaling,
0540 const bool isHadron,
0541 const bool isbHadron,
0542 const bool isParton,
0543 const bool isLepton,
0544 std::vector<fastjet::PseudoJet>& constituents) {
0545
0546 for (reco::GenParticleRefVector::const_iterator it = particles->begin(); it != particles->end(); ++it) {
0547 if ((*it)->pt() == 0) {
0548 edm::LogInfo("NullTransverseMomentum") << "dropping input ghost candidate with pt=0";
0549 continue;
0550 }
0551 fastjet::PseudoJet p((*it)->px(), (*it)->py(), (*it)->pz(), (*it)->energy());
0552 p *= ghostRescaling;
0553 p.set_user_info(new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
0554 constituents.push_back(p);
0555 }
0556 }
0557
0558
0559 void JetFlavourClustering::matchReclusteredJets(const edm::Handle<edm::View<reco::Jet>>& jets,
0560 const std::vector<fastjet::PseudoJet>& reclusteredJets,
0561 std::vector<int>& matchedIndices) {
0562 std::vector<bool> matchedLocks(reclusteredJets.size(), false);
0563
0564 for (size_t j = 0; j < jets->size(); ++j) {
0565 double matchedDR2 = 1e9;
0566 int matchedIdx = -1;
0567
0568 for (size_t rj = 0; rj < reclusteredJets.size(); ++rj) {
0569 if (matchedLocks.at(rj))
0570 continue;
0571
0572 double tempDR2 = reco::deltaR2(jets->at(j).rapidity(),
0573 jets->at(j).phi(),
0574 reclusteredJets.at(rj).rapidity(),
0575 reclusteredJets.at(rj).phi_std());
0576 if (tempDR2 < matchedDR2) {
0577 matchedDR2 = tempDR2;
0578 matchedIdx = rj;
0579 }
0580 }
0581
0582 if (matchedIdx >= 0) {
0583 if (matchedDR2 > rParam_ * rParam_) {
0584 edm::LogError("JetMatchingFailed") << "Matched reclustered jet " << matchedIdx << " and original jet " << j
0585 << " are separated by dR=" << sqrt(matchedDR2)
0586 << " which is greater than the jet size R=" << rParam_ << ".\n"
0587 << "This is not expected so please check that the jet algorithm and jet "
0588 "size match those used for the original jet collection.";
0589 } else
0590 matchedLocks.at(matchedIdx) = true;
0591 } else
0592 edm::LogError("JetMatchingFailed") << "Matching reclustered to original jets failed. Please check that the jet "
0593 "algorithm and jet size match those used for the original jet collection.";
0594
0595 matchedIndices.push_back(matchedIdx);
0596 }
0597 }
0598
0599
0600 void JetFlavourClustering::matchGroomedJets(const edm::Handle<edm::View<reco::Jet>>& jets,
0601 const edm::Handle<edm::View<reco::Jet>>& groomedJets,
0602 std::vector<int>& matchedIndices) {
0603 std::vector<bool> jetLocks(jets->size(), false);
0604 std::vector<int> jetIndices;
0605
0606 for (size_t gj = 0; gj < groomedJets->size(); ++gj) {
0607 double matchedDR2 = 1e9;
0608 int matchedIdx = -1;
0609
0610 if (groomedJets->at(gj).pt() > 0.)
0611 {
0612 for (size_t j = 0; j < jets->size(); ++j) {
0613 if (jetLocks.at(j))
0614 continue;
0615
0616 double tempDR2 = reco::deltaR2(
0617 jets->at(j).rapidity(), jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi());
0618 if (tempDR2 < matchedDR2) {
0619 matchedDR2 = tempDR2;
0620 matchedIdx = j;
0621 }
0622 }
0623 }
0624
0625 if (matchedIdx >= 0) {
0626 if (matchedDR2 > rParam_ * rParam_) {
0627 edm::LogWarning("MatchedJetsFarApart")
0628 << "Matched groomed jet " << gj << " and original jet " << matchedIdx
0629 << " are separated by dR=" << sqrt(matchedDR2) << " which is greater than the jet size R=" << rParam_
0630 << ".\n"
0631 << "This is not expected so the matching of these two jets has been discarded. Please check that the two "
0632 "jet collections belong to each other.";
0633 matchedIdx = -1;
0634 } else
0635 jetLocks.at(matchedIdx) = true;
0636 }
0637 jetIndices.push_back(matchedIdx);
0638 }
0639
0640 for (size_t j = 0; j < jets->size(); ++j) {
0641 std::vector<int>::iterator matchedIndex = std::find(jetIndices.begin(), jetIndices.end(), j);
0642
0643 matchedIndices.push_back(matchedIndex != jetIndices.end() ? std::distance(jetIndices.begin(), matchedIndex) : -1);
0644 }
0645 }
0646
0647
0648 void JetFlavourClustering::matchSubjets(const std::vector<int>& groomedIndices,
0649 const edm::Handle<edm::View<reco::Jet>>& groomedJets,
0650 const edm::Handle<edm::View<reco::Jet>>& subjets,
0651 std::vector<std::vector<int>>& matchedIndices) {
0652 for (size_t g = 0; g < groomedIndices.size(); ++g) {
0653 std::vector<int> subjetIndices;
0654
0655 if (groomedIndices.at(g) >= 0) {
0656 for (size_t s = 0; s < groomedJets->at(groomedIndices.at(g)).numberOfDaughters(); ++s) {
0657 const edm::Ptr<reco::Candidate>& subjet = groomedJets->at(groomedIndices.at(g)).daughterPtr(s);
0658
0659 for (size_t sj = 0; sj < subjets->size(); ++sj) {
0660 if (subjet == edm::Ptr<reco::Candidate>(subjets->ptrAt(sj))) {
0661 subjetIndices.push_back(sj);
0662 break;
0663 }
0664 }
0665 }
0666
0667 if (subjetIndices.empty())
0668 edm::LogError("SubjetMatchingFailed") << "Matching subjets to original jets failed. Please check that the "
0669 "groomed jet and subjet collections belong to each other.";
0670
0671 matchedIndices.push_back(subjetIndices);
0672 } else
0673 matchedIndices.push_back(subjetIndices);
0674 }
0675 }
0676
0677
0678 void JetFlavourClustering::setFlavours(const reco::GenParticleRefVector& clusteredbHadrons,
0679 const reco::GenParticleRefVector& clusteredcHadrons,
0680 const reco::GenParticleRefVector& clusteredPartons,
0681 int& hadronFlavour,
0682 int& partonFlavour) {
0683 reco::GenParticleRef hardestParton;
0684 reco::GenParticleRef hardestLightParton;
0685 reco::GenParticleRef flavourParton;
0686
0687
0688 for (reco::GenParticleRefVector::const_iterator it = clusteredPartons.begin(); it != clusteredPartons.end(); ++it) {
0689
0690 if (hardestParton.isNull())
0691 hardestParton = (*it);
0692
0693 if (hardestLightParton.isNull()) {
0694 if (CandMCTagUtils::isLightParton(*(*it)))
0695 hardestLightParton = (*it);
0696 }
0697
0698 if (flavourParton.isNull() && (std::abs((*it)->pdgId()) == 4))
0699 flavourParton = (*it);
0700
0701 if (std::abs((*it)->pdgId()) == 5) {
0702 if (flavourParton.isNull())
0703 flavourParton = (*it);
0704 else if (std::abs(flavourParton->pdgId()) != 5)
0705 flavourParton = (*it);
0706 }
0707 }
0708
0709
0710 if (!clusteredbHadrons.empty())
0711 hadronFlavour = 5;
0712 else if (!clusteredcHadrons.empty() && clusteredbHadrons.empty())
0713 hadronFlavour = 4;
0714
0715 if (flavourParton.isNull()) {
0716 if (hardestParton.isNonnull())
0717 partonFlavour = hardestParton->pdgId();
0718 } else
0719 partonFlavour = flavourParton->pdgId();
0720
0721
0722 if (hadronFlavourHasPriority_) {
0723 if (hadronFlavour == 0 && (std::abs(partonFlavour) == 4 || std::abs(partonFlavour) == 5))
0724 partonFlavour = (hardestLightParton.isNonnull() ? hardestLightParton->pdgId() : 0);
0725 else if (hadronFlavour != 0 && std::abs(partonFlavour) != hadronFlavour)
0726 partonFlavour = hadronFlavour;
0727 }
0728 }
0729
0730
0731 void JetFlavourClustering::assignToSubjets(const reco::GenParticleRefVector& clusteredParticles,
0732 const edm::Handle<edm::View<reco::Jet>>& subjets,
0733 const std::vector<int>& subjetIndices,
0734 std::vector<reco::GenParticleRefVector>& assignedParticles) {
0735
0736 for (reco::GenParticleRefVector::const_iterator it = clusteredParticles.begin(); it != clusteredParticles.end();
0737 ++it) {
0738 std::vector<double> dR2toSubjets;
0739
0740 for (size_t sj = 0; sj < subjetIndices.size(); ++sj)
0741 dR2toSubjets.push_back(reco::deltaR2((*it)->rapidity(),
0742 (*it)->phi(),
0743 subjets->at(subjetIndices.at(sj)).rapidity(),
0744 subjets->at(subjetIndices.at(sj)).phi()));
0745
0746
0747 int closestSubjetIdx =
0748 std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
0749
0750 assignedParticles.at(closestSubjetIdx).push_back(*it);
0751 }
0752 }
0753
0754
0755 void JetFlavourClustering::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0756
0757
0758 edm::ParameterSetDescription desc;
0759 desc.setUnknown();
0760 descriptions.addDefault(desc);
0761 }
0762
0763
0764 DEFINE_FWK_MODULE(JetFlavourClustering);