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,
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);
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);
edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
std::shared_ptr< fastjet::JetDefinition > JetDefPtr
bool isLightParton(const reco::Candidate &c)
bool empty() const
Is the RefVector empty.
T getParameter(std::string const &) const
const bool isLepton() const
Clusters hadrons, partons, and jet contituents to determine the jet flavour.
const bool hadronFlavourHasPriority_
void insertGhosts(const edm::Handle< reco::GenParticleRefVector > &particles, const double ghostRescaling, const bool isHadron, const bool isbHadron, const bool isParton, const bool isLepton, std::vector< fastjet::PseudoJet > &constituents)
const bool isParton() const
GhostInfo(const bool &isHadron, const bool &isbHadron, const bool &isParton, const bool &isLepton, const reco::GenParticleRef &particleRef)
edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
void assignToSubjets(const reco::GenParticleRefVector &clusteredParticles, const edm::Handle< edm::View< reco::Jet >> &subjets, const std::vector< int > &subjetIndices, std::vector< reco::GenParticleRefVector > &assignedParticles)
const reco::GenParticleRef m_particleRef
constexpr bool isUninitialized() const noexcept
void setFlavours(const reco::GenParticleRefVector &clusteredbHadrons, const reco::GenParticleRefVector &clusteredcHadrons, const reco::GenParticleRefVector &clusteredPartons, int &hadronFlavour, int &partonFlavour)
const edm::EDGetTokenT< reco::GenParticleRefVector > bHadronsToken_
bool isNonnull() const
Checks for non-null.
bool isLepton(const Candidate &part)
bool existsAs(std::string const ¶meterName, bool trackiness=true) const
checks if a parameter exists as a given type
Log< level::Error, false > LogError
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
const double ghostRescaling_
edm::EDGetTokenT< edm::ValueMap< float > > weightsToken_
const edm::EDGetTokenT< reco::GenParticleRefVector > partonsToken_
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
JetDefPtr fjJetDefinition_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
edm::RefToBaseProd< reco::Jet > JetRefBaseProd
const edm::EDGetTokenT< reco::GenParticleRefVector > cHadronsToken_
void addDefault(ParameterSetDescription const &psetDescription)
void matchReclusteredJets(const edm::Handle< edm::View< reco::Jet >> &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices)
bool isNonnull() const
Checks for non-null.
Class storing the jet flavour information.
Abs< T >::type abs(const T &t)
#define DEFINE_FWK_MODULE(type)
JetFlavourClustering(const edm::ParameterSet &)
bool isNull() const
Checks for null.
void matchGroomedJets(const edm::Handle< edm::View< reco::Jet >> &jets, const edm::Handle< edm::View< reco::Jet >> &matchedJets, std::vector< int > &matchedIndices)
const std::string jetAlgorithm_
Log< level::Info, false > LogInfo
edm::RefVector< GenParticleCollection > GenParticleRefVector
vector of reference to GenParticle in the same collection
const reco::GenParticleRef & particleRef() const
std::shared_ptr< fastjet::ClusterSequence > ClusterSequencePtr
const edm::EDGetTokenT< edm::View< reco::Jet > > jetsToken_
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
bool isParton(const reco::Candidate &c)
const_iterator end() const
Termination of iteration.
void produce(edm::Event &, const edm::EventSetup &) override
const double relPtTolerance_
boost::indirect_iterator< typename seq_t::const_iterator > const_iterator
edm::EDGetTokenT< edm::View< reco::Jet > > groomedJetsToken_
void push_back(value_type const &ref)
Add a Ref<C, T> to the RefVector.
void matchSubjets(const std::vector< int > &groomedIndices, const edm::Handle< edm::View< reco::Jet >> &groomedJets, const edm::Handle< edm::View< reco::Jet >> &subjets, std::vector< std::vector< int >> &matchedIndices)
Log< level::Warning, false > LogWarning
const_iterator begin() const
Initialize an iterator over the RefVector.
const bool isbHadron() const
ClusterSequencePtr fjClusterSeq_
~JetFlavourClustering() override
const bool isHadron() const