99 #include "fastjet/JetDefinition.hh" 100 #include "fastjet/ClusterSequence.hh" 101 #include "fastjet/Selector.hh" 102 #include "fastjet/PseudoJet.hh" 108 typedef std::shared_ptr<fastjet::JetDefinition>
JetDefPtr;
113 class GhostInfo :
public fastjet::PseudoJet::UserInfoBase {
159 std::vector<fastjet::PseudoJet>& constituents);
162 const std::vector<fastjet::PseudoJet>& matchedJets,
163 std::vector<int>& matchedIndices);
166 std::vector<int>& matchedIndices);
167 void matchSubjets(
const std::vector<int>& groomedIndices,
170 std::vector<std::vector<int> >& matchedIndices);
180 const std::vector<int>& subjetIndices,
181 std::vector<reco::GenParticleRefVector>& assignedParticles);
219 jetAlgorithm_(iConfig.getParameter<
std::
string>(
"jetAlgorithm")),
220 rParam_(iConfig.getParameter<double>(
"rParam")),
223 ghostRescaling_(iConfig.exists(
"ghostRescaling") ? iConfig.getParameter<double>(
"ghostRescaling") : 1
e-18),
225 iConfig.exists(
"relPtTolerance")
226 ? iConfig.getParameter<double>(
"relPtTolerance")
228 hadronFlavourHasPriority_(iConfig.getParameter<
bool>(
"hadronFlavourHasPriority")),
229 useSubjets_(iConfig.exists(
"groomedJets") && iConfig.exists(
"subjets")),
230 useLeptons_(iConfig.exists(
"leptons"))
234 produces<reco::JetFlavourInfoMatchingCollection>();
236 produces<reco::JetFlavourInfoMatchingCollection>(
"SubJets");
247 <<
", use CambridgeAachen | Kt | AntiKt" << std::endl;
293 std::unique_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
295 subjetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(
reco::JetRefBaseProd(subjets));
298 std::vector<fastjet::PseudoJet> fjInputs;
299 unsigned int reserve = jets->size() * 128 + bHadrons->
size() + cHadrons->
size() + partons->
size();
301 reserve += leptons->
size();
302 fjInputs.reserve(reserve);
305 std::vector<edm::Ptr<reco::Candidate> > constituents = it->getJetConstituents();
306 std::vector<edm::Ptr<reco::Candidate> >::const_iterator
m;
307 for (m = constituents.begin(); m != constituents.end(); ++
m) {
310 edm::LogError(
"MissingJetConstituent") <<
"Jet constituent required for jet reclustering is missing. " 311 "Reclustered jets are not guaranteed to reproduce the original jets!";
314 if (constit->pt() == 0) {
315 edm::LogWarning(
"NullTransverseMomentum") <<
"dropping input candidate with pt=0";
318 fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
334 std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(
fjClusterSeq_->inclusive_jets(
jetPtMin_));
336 if (inclusiveJets.size() < jets->size())
338 <<
"There are fewer reclustered (" << inclusiveJets.size() <<
") than original jets (" << jets->size()
339 <<
"). Please check that the jet algorithm and jet size match those used for the original jet collection.";
342 std::vector<int> reclusteredIndices;
346 std::vector<int> groomedIndices;
348 if (groomedJets->size() > jets->size())
350 <<
"There are more groomed (" << groomedJets->size() <<
") than original jets (" << jets->size()
351 <<
"). Please check that the two jet collections belong to each other.";
357 std::vector<std::vector<int> > subjetIndices;
359 matchSubjets(groomedIndices, groomedJets, subjets, subjetIndices);
363 for (
size_t i = 0;
i < jets->size(); ++
i) {
370 if (reclusteredIndices.at(
i) < 0) {
372 (*jetFlavourInfos)[jets->refAt(
i)] =
373 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
374 }
else if (jets->at(
i).pt() == 0) {
376 <<
"The original jet " <<
i <<
" has Pt=0. This is not expected so the jet will be skipped.";
379 (*jetFlavourInfos)[jets->refAt(
i)] =
380 reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
385 for (
size_t sj = 0; sj < subjetIndices.at(
i).size(); ++sj) {
387 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
398 if ((
std::abs(inclusiveJets.at(reclusteredIndices.at(
i)).
pt() - jets->at(
i).pt()) / jets->at(
i).pt()) >
400 if (jets->at(
i).pt() < 10.)
402 <<
"The reclustered and original jet " <<
i <<
" have different Pt's (" 403 << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " << jets->at(
i).pt()
404 <<
" GeV, respectively).\n" 405 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection " 406 "and also make sure the original jets are uncorrected. In addition, make sure you are not using " 407 "CaloJets which are presently not supported.\n" 408 <<
"Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n" 409 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision " 410 "in which case make sure the original jet collection is produced and reclustering is performed in the " 414 <<
"The reclustered and original jet " <<
i <<
" have different Pt's (" 415 << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " << jets->at(
i).pt()
416 <<
" GeV, respectively).\n" 417 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection " 418 "and also make sure the original jets are uncorrected. In addition, make sure you are not using " 419 "CaloJets which are presently not supported.\n" 420 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision " 421 "in which case make sure the original jet collection is produced and reclustering is performed in the " 426 std::vector<fastjet::PseudoJet> constituents =
427 fastjet::sorted_by_pt(inclusiveJets.at(reclusteredIndices.at(
i)).constituents());
430 for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it) {
431 if (!it->has_user_info())
455 setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
459 clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
464 if (subjetIndices.at(
i).empty())
468 std::vector<reco::GenParticleRefVector> assignedbHadrons(subjetIndices.at(
i).size(),
470 std::vector<reco::GenParticleRefVector> assignedcHadrons(subjetIndices.at(
i).size(),
476 assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(
i), assignedbHadrons);
478 assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(
i), assignedcHadrons);
480 assignToSubjets(clusteredPartons, subjets, subjetIndices.at(
i), assignedPartons);
483 assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(
i), assignedLeptons);
486 for (
size_t sj = 0; sj < subjetIndices.at(
i).size(); ++sj) {
487 int subjetHadronFlavour = 0;
488 int subjetPartonFlavour = 0;
492 assignedcHadrons.at(sj),
493 assignedPartons.at(sj),
495 subjetPartonFlavour);
498 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
500 assignedcHadrons.at(sj),
501 assignedPartons.at(sj),
502 assignedLeptons.at(sj),
504 subjetPartonFlavour);
523 const bool isbHadron,
526 std::vector<fastjet::PseudoJet>& constituents) {
529 if ((*it)->pt() == 0) {
530 edm::LogInfo(
"NullTransverseMomentum") <<
"dropping input ghost candidate with pt=0";
533 fastjet::PseudoJet
p((*it)->px(), (*it)->py(), (*it)->pz(), (*it)->energy());
535 p.set_user_info(
new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
536 constituents.push_back(p);
542 const std::vector<fastjet::PseudoJet>& reclusteredJets,
543 std::vector<int>& matchedIndices) {
544 std::vector<bool> matchedLocks(reclusteredJets.size(),
false);
546 for (
size_t j = 0;
j <
jets->size(); ++
j) {
547 double matchedDR2 = 1e9;
550 for (
size_t rj = 0; rj < reclusteredJets.size(); ++rj) {
551 if (matchedLocks.at(rj))
556 reclusteredJets.at(rj).rapidity(),
557 reclusteredJets.at(rj).phi_std());
558 if (tempDR2 < matchedDR2) {
559 matchedDR2 = tempDR2;
564 if (matchedIdx >= 0) {
566 edm::LogError(
"JetMatchingFailed") <<
"Matched reclustered jet " << matchedIdx <<
" and original jet " <<
j 567 <<
" are separated by dR=" <<
sqrt(matchedDR2)
568 <<
" which is greater than the jet size R=" << rParam_ <<
".\n" 569 <<
"This is not expected so please check that the jet algorithm and jet " 570 "size match those used for the original jet collection.";
572 matchedLocks.at(matchedIdx) =
true;
574 edm::LogError(
"JetMatchingFailed") <<
"Matching reclustered to original jets failed. Please check that the jet " 575 "algorithm and jet size match those used for the original jet collection.";
577 matchedIndices.push_back(matchedIdx);
584 std::vector<int>& matchedIndices) {
585 std::vector<bool> jetLocks(
jets->size(),
false);
586 std::vector<int> jetIndices;
588 for (
size_t gj = 0; gj < groomedJets->size(); ++gj) {
589 double matchedDR2 = 1e9;
592 if (groomedJets->at(gj).pt() > 0.)
594 for (
size_t j = 0;
j <
jets->size(); ++
j) {
599 jets->at(
j).rapidity(),
jets->at(
j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi());
600 if (tempDR2 < matchedDR2) {
601 matchedDR2 = tempDR2;
607 if (matchedIdx >= 0) {
610 <<
"Matched groomed jet " << gj <<
" and original jet " << matchedIdx
611 <<
" are separated by dR=" <<
sqrt(matchedDR2) <<
" which is greater than the jet size R=" << rParam_
613 <<
"This is not expected so the matching of these two jets has been discarded. Please check that the two " 614 "jet collections belong to each other.";
617 jetLocks.at(matchedIdx) =
true;
619 jetIndices.push_back(matchedIdx);
622 for (
size_t j = 0;
j <
jets->size(); ++
j) {
623 std::vector<int>::iterator matchedIndex =
std::find(jetIndices.begin(), jetIndices.end(),
j);
625 matchedIndices.push_back(matchedIndex != jetIndices.end() ?
std::distance(jetIndices.begin(), matchedIndex) : -1);
633 std::vector<std::vector<int> >& matchedIndices) {
634 for (
size_t g = 0;
g < groomedIndices.size(); ++
g) {
635 std::vector<int> subjetIndices;
637 if (groomedIndices.at(
g) >= 0) {
638 for (
size_t s = 0;
s < groomedJets->at(groomedIndices.at(
g)).numberOfDaughters(); ++
s) {
641 for (
size_t sj = 0; sj < subjets->size(); ++sj) {
643 subjetIndices.push_back(sj);
649 if (subjetIndices.empty())
650 edm::LogError(
"SubjetMatchingFailed") <<
"Matching subjets to original jets failed. Please check that the " 651 "groomed jet and subjet collections belong to each other.";
653 matchedIndices.push_back(subjetIndices);
655 matchedIndices.push_back(subjetIndices);
672 if (hardestParton.
isNull())
673 hardestParton = (*it);
675 if (hardestLightParton.
isNull()) {
677 hardestLightParton = (*it);
681 flavourParton = (*it);
683 if (
std::abs((*it)->pdgId()) == 5) {
684 if (flavourParton.
isNull())
685 flavourParton = (*it);
686 else if (
std::abs(flavourParton->pdgId()) != 5)
687 flavourParton = (*it);
692 if (!clusteredbHadrons.
empty())
694 else if (!clusteredcHadrons.
empty() && clusteredbHadrons.
empty())
697 if (flavourParton.
isNull()) {
699 partonFlavour = hardestParton->pdgId();
701 partonFlavour = flavourParton->pdgId();
705 if (hadronFlavour == 0 && (
std::abs(partonFlavour) == 4 ||
std::abs(partonFlavour) == 5))
706 partonFlavour = (hardestLightParton.
isNonnull() ? hardestLightParton->pdgId() : 0);
708 partonFlavour = hadronFlavour;
715 const std::vector<int>& subjetIndices,
716 std::vector<reco::GenParticleRefVector>& assignedParticles) {
720 std::vector<double> dR2toSubjets;
722 for (
size_t sj = 0; sj < subjetIndices.size(); ++sj)
725 subjets->at(subjetIndices.at(sj)).rapidity(),
726 subjets->at(subjetIndices.at(sj)).
phi()));
729 int closestSubjetIdx =
730 std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
732 assignedParticles.at(closestSubjetIdx).push_back(*it);
const reco::GenParticleRef & particleRef() const
edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
std::shared_ptr< fastjet::JetDefinition > JetDefPtr
T getParameter(std::string const &) const
bool isLightParton(const reco::Candidate &c)
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
bool isNonnull() const
Checks for non-null.
void assignToSubjets(const reco::GenParticleRefVector &clusteredParticles, const edm::Handle< edm::View< reco::Jet > > &subjets, const std::vector< int > &subjetIndices, std::vector< reco::GenParticleRefVector > &assignedParticles)
Clusters hadrons, partons, and jet contituents to determine the jet flavour.
const bool hadronFlavourHasPriority_
bool getByToken(EDGetToken token, Handle< PROD > &result) const
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)
GhostInfo(const bool &isHadron, const bool &isbHadron, const bool &isParton, const bool &isLepton, const reco::GenParticleRef &particleRef)
edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
const reco::GenParticleRef m_particleRef
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 isLepton(const Candidate &part)
void matchGroomedJets(const edm::Handle< edm::View< reco::Jet > > &jets, const edm::Handle< edm::View< reco::Jet > > &matchedJets, std::vector< int > &matchedIndices)
const_iterator end() const
Termination of iteration.
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
bool empty() const
Is the RefVector empty.
const double ghostRescaling_
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
const bool isParton() const
const_iterator begin() const
Initialize an iterator over the RefVector.
JetDefPtr fjJetDefinition_
const bool isLepton() const
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
edm::RefToBaseProd< reco::Jet > JetRefBaseProd
const edm::EDGetTokenT< reco::GenParticleRefVector > cHadronsToken_
#define DEFINE_FWK_MODULE(type)
void addDefault(ParameterSetDescription const &psetDescription)
Class storing the jet flavour information.
Abs< T >::type abs(const T &t)
JetFlavourClustering(const edm::ParameterSet &)
bool isNull() const
Checks for null.
bool isNonnull() const
Checks for non-null.
void matchReclusteredJets(const edm::Handle< edm::View< reco::Jet > > &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices)
const std::string jetAlgorithm_
edm::RefVector< GenParticleCollection > GenParticleRefVector
vector of reference to GenParticle in the same collection
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())
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
bool isParton(const reco::Candidate &c)
void produce(edm::Event &, const edm::EventSetup &) override
const double relPtTolerance_
boost::indirect_iterator< typename seq_t::const_iterator > const_iterator
const bool isbHadron() const
edm::EDGetTokenT< edm::View< reco::Jet > > groomedJetsToken_
const bool isHadron() const
void push_back(value_type const &ref)
Add a Ref<C, T> to the RefVector.
size_type size() const
Size of 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)
ClusterSequencePtr fjClusterSeq_
~JetFlavourClustering() override