100 #include "fastjet/JetDefinition.hh"
101 #include "fastjet/ClusterSequence.hh"
102 #include "fastjet/Selector.hh"
103 #include "fastjet/PseudoJet.hh"
109 typedef std::shared_ptr<fastjet::JetDefinition>
JetDefPtr;
114 class GhostInfo :
public fastjet::PseudoJet::UserInfoBase {
157 const bool isbHadron,
160 std::vector<fastjet::PseudoJet>& constituents);
163 const std::vector<fastjet::PseudoJet>& matchedJets,
164 std::vector<int>& matchedIndices);
167 std::vector<int>& matchedIndices);
168 void matchSubjets(
const std::vector<int>& groomedIndices,
171 std::vector<std::vector<int>>& matchedIndices);
181 const std::vector<int>& subjetIndices,
182 std::vector<reco::GenParticleRefVector>& assignedParticles);
220 jetAlgorithm_(iConfig.getParameter<
std::
string>(
"jetAlgorithm")),
221 rParam_(iConfig.getParameter<double>(
"rParam")),
225 ghostRescaling_(iConfig.exists(
"ghostRescaling") ? iConfig.getParameter<double>(
"ghostRescaling") : 1
e-18),
227 iConfig.exists(
"relPtTolerance")
228 ? iConfig.getParameter<double>(
"relPtTolerance")
230 hadronFlavourHasPriority_(iConfig.getParameter<
bool>(
"hadronFlavourHasPriority")),
231 useSubjets_(iConfig.exists(
"groomedJets") && iConfig.exists(
"subjets")),
232 useLeptons_(iConfig.exists(
"leptons"))
236 produces<reco::JetFlavourInfoMatchingCollection>();
241 produces<reco::JetFlavourInfoMatchingCollection>(
"SubJets");
252 <<
", use CambridgeAachen | Kt | AntiKt" << std::endl;
302 std::unique_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
304 subjetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(
reco::JetRefBaseProd(subjets));
307 std::vector<fastjet::PseudoJet> fjInputs;
311 fjInputs.reserve(reserve);
314 std::vector<edm::Ptr<reco::Candidate>> constituents = it->getJetConstituents();
315 std::vector<edm::Ptr<reco::Candidate>>::const_iterator
m;
316 for (
m = constituents.begin();
m != constituents.end(); ++
m) {
319 edm::LogError(
"MissingJetConstituent") <<
"Jet constituent required for jet reclustering is missing. "
320 "Reclustered jets are not guaranteed to reproduce the original jets!";
323 if (constit->pt() == 0) {
324 edm::LogWarning(
"NullTransverseMomentum") <<
"dropping input candidate with pt=0";
327 if (it->isWeighted()) {
330 <<
"JetFlavourClustering: No weights (e.g. PUPPI) given for weighted jet collection" << std::endl;
331 float w = (*weights)[constit];
333 fastjet::PseudoJet(constit->px() *
w, constit->py() *
w, constit->pz() *
w, constit->energy() *
w));
335 fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
352 std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(
fjClusterSeq_->inclusive_jets(
jetPtMin_));
354 if (inclusiveJets.size() <
jets->size())
356 <<
"There are fewer reclustered (" << inclusiveJets.size() <<
") than original jets (" <<
jets->size()
357 <<
"). Please check that the jet algorithm and jet size match those used for the original jet collection.";
360 std::vector<int> reclusteredIndices;
364 std::vector<int> groomedIndices;
366 if (groomedJets->size() >
jets->size())
368 <<
"There are more groomed (" << groomedJets->size() <<
") than original jets (" <<
jets->size()
369 <<
"). Please check that the two jet collections belong to each other.";
375 std::vector<std::vector<int>> subjetIndices;
377 matchSubjets(groomedIndices, groomedJets, subjets, subjetIndices);
381 for (
size_t i = 0;
i <
jets->size(); ++
i) {
388 if (reclusteredIndices.at(
i) < 0) {
390 (*jetFlavourInfos)[
jets->refAt(
i)] =
391 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
392 }
else if (
jets->at(
i).pt() == 0) {
394 <<
"The original jet " <<
i <<
" has Pt=0. This is not expected so the jet will be skipped.";
397 (*jetFlavourInfos)[
jets->refAt(
i)] =
398 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
403 for (
size_t sj = 0; sj < subjetIndices.at(
i).size(); ++sj) {
405 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
416 if ((
std::abs(inclusiveJets.at(reclusteredIndices.at(
i)).
pt() -
jets->at(
i).pt()) /
jets->at(
i).pt()) >
418 if (
jets->at(
i).pt() < 10.)
420 <<
"The reclustered and original jet " <<
i <<
" have different Pt's ("
421 << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " <<
jets->at(
i).pt()
422 <<
" GeV, respectively).\n"
423 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection "
424 "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
425 "CaloJets which are presently not supported.\n"
426 <<
"Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n"
427 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision "
428 "in which case make sure the original jet collection is produced and reclustering is performed in the "
432 <<
"The reclustered and original jet " <<
i <<
" have different Pt's ("
433 << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " <<
jets->at(
i).pt()
434 <<
" GeV, respectively).\n"
435 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection "
436 "and also make sure the original jets are uncorrected. In addition, make sure you are not using "
437 "CaloJets which are presently not supported.\n"
438 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision "
439 "in which case make sure the original jet collection is produced and reclustering is performed in the "
444 std::vector<fastjet::PseudoJet> constituents =
445 fastjet::sorted_by_pt(inclusiveJets.at(reclusteredIndices.at(
i)).constituents());
448 for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it) {
449 if (!it->has_user_info())
482 if (subjetIndices.at(
i).empty())
486 std::vector<reco::GenParticleRefVector> assignedbHadrons(subjetIndices.at(
i).size(),
488 std::vector<reco::GenParticleRefVector> assignedcHadrons(subjetIndices.at(
i).size(),
494 assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(
i), assignedbHadrons);
496 assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(
i), assignedcHadrons);
498 assignToSubjets(clusteredPartons, subjets, subjetIndices.at(
i), assignedPartons);
501 assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(
i), assignedLeptons);
504 for (
size_t sj = 0; sj < subjetIndices.at(
i).size(); ++sj) {
505 int subjetHadronFlavour = 0;
506 int subjetPartonFlavour = 0;
510 assignedcHadrons.at(sj),
511 assignedPartons.at(sj),
513 subjetPartonFlavour);
516 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
518 assignedcHadrons.at(sj),
519 assignedPartons.at(sj),
520 assignedLeptons.at(sj),
522 subjetPartonFlavour);
541 const bool isbHadron,
544 std::vector<fastjet::PseudoJet>& constituents) {
547 if ((*it)->pt() == 0) {
548 edm::LogInfo(
"NullTransverseMomentum") <<
"dropping input ghost candidate with pt=0";
551 fastjet::PseudoJet
p((*it)->px(), (*it)->py(), (*it)->pz(), (*it)->energy());
554 constituents.push_back(
p);
560 const std::vector<fastjet::PseudoJet>& reclusteredJets,
561 std::vector<int>& matchedIndices) {
562 std::vector<bool> matchedLocks(reclusteredJets.size(),
false);
564 for (
size_t j = 0;
j <
jets->size(); ++
j) {
565 double matchedDR2 = 1e9;
568 for (
size_t rj = 0; rj < reclusteredJets.size(); ++rj) {
569 if (matchedLocks.at(rj))
574 reclusteredJets.at(rj).rapidity(),
575 reclusteredJets.at(rj).phi_std());
576 if (tempDR2 < matchedDR2) {
577 matchedDR2 = tempDR2;
582 if (matchedIdx >= 0) {
584 edm::LogError(
"JetMatchingFailed") <<
"Matched reclustered jet " << matchedIdx <<
" and original jet " <<
j
585 <<
" are separated by dR=" <<
sqrt(matchedDR2)
586 <<
" which is greater than the jet size R=" <<
rParam_ <<
".\n"
587 <<
"This is not expected so please check that the jet algorithm and jet "
588 "size match those used for the original jet collection.";
590 matchedLocks.at(matchedIdx) =
true;
592 edm::LogError(
"JetMatchingFailed") <<
"Matching reclustered to original jets failed. Please check that the jet "
593 "algorithm and jet size match those used for the original jet collection.";
595 matchedIndices.push_back(matchedIdx);
602 std::vector<int>& matchedIndices) {
603 std::vector<bool> jetLocks(
jets->size(),
false);
604 std::vector<int> jetIndices;
606 for (
size_t gj = 0; gj < groomedJets->size(); ++gj) {
607 double matchedDR2 = 1e9;
610 if (groomedJets->at(gj).pt() > 0.)
612 for (
size_t j = 0;
j <
jets->size(); ++
j) {
617 jets->at(
j).rapidity(),
jets->at(
j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi());
618 if (tempDR2 < matchedDR2) {
619 matchedDR2 = tempDR2;
625 if (matchedIdx >= 0) {
628 <<
"Matched groomed jet " << gj <<
" and original jet " << matchedIdx
629 <<
" are separated by dR=" <<
sqrt(matchedDR2) <<
" which is greater than the jet size R=" <<
rParam_
631 <<
"This is not expected so the matching of these two jets has been discarded. Please check that the two "
632 "jet collections belong to each other.";
635 jetLocks.at(matchedIdx) =
true;
637 jetIndices.push_back(matchedIdx);
640 for (
size_t j = 0;
j <
jets->size(); ++
j) {
641 std::vector<int>::iterator matchedIndex =
std::find(jetIndices.begin(), jetIndices.end(),
j);
643 matchedIndices.push_back(matchedIndex != jetIndices.end() ?
std::distance(jetIndices.begin(), matchedIndex) : -1);
651 std::vector<std::vector<int>>& matchedIndices) {
652 for (
size_t g = 0;
g < groomedIndices.size(); ++
g) {
653 std::vector<int> subjetIndices;
655 if (groomedIndices.at(
g) >= 0) {
656 for (
size_t s = 0;
s < groomedJets->at(groomedIndices.at(
g)).numberOfDaughters(); ++
s) {
659 for (
size_t sj = 0; sj < subjets->size(); ++sj) {
661 subjetIndices.push_back(sj);
667 if (subjetIndices.empty())
668 edm::LogError(
"SubjetMatchingFailed") <<
"Matching subjets to original jets failed. Please check that the "
669 "groomed jet and subjet collections belong to each other.";
671 matchedIndices.push_back(subjetIndices);
673 matchedIndices.push_back(subjetIndices);
690 if (hardestParton.
isNull())
691 hardestParton = (*it);
693 if (hardestLightParton.
isNull()) {
695 hardestLightParton = (*it);
699 flavourParton = (*it);
701 if (
std::abs((*it)->pdgId()) == 5) {
702 if (flavourParton.
isNull())
703 flavourParton = (*it);
704 else if (
std::abs(flavourParton->pdgId()) != 5)
705 flavourParton = (*it);
710 if (!clusteredbHadrons.
empty())
712 else if (!clusteredcHadrons.
empty() && clusteredbHadrons.
empty())
715 if (flavourParton.
isNull()) {
733 const std::vector<int>& subjetIndices,
734 std::vector<reco::GenParticleRefVector>& assignedParticles) {
738 std::vector<double> dR2toSubjets;
740 for (
size_t sj = 0; sj < subjetIndices.size(); ++sj)
743 subjets->at(subjetIndices.at(sj)).rapidity(),
744 subjets->at(subjetIndices.at(sj)).
phi()));
747 int closestSubjetIdx =
748 std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
750 assignedParticles.at(closestSubjetIdx).push_back(*it);