CMS 3D CMS Logo

List of all members | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes
JetFlavourClustering Class Reference

Clusters hadrons, partons, and jet contituents to determine the jet flavour. More...

#include <PhysicsTools/JetMCAlgos/plugins/JetFlavourClustering.cc>

Inheritance diagram for JetFlavourClustering:
edm::stream::EDProducer<>

Public Member Functions

 JetFlavourClustering (const edm::ParameterSet &)
 
 ~JetFlavourClustering () override
 
- Public Member Functions inherited from edm::stream::EDProducer<>
 EDProducer ()=default
 
bool hasAbilityToProduceInBeginLumis () const final
 
bool hasAbilityToProduceInBeginRuns () const final
 
bool hasAbilityToProduceInEndLumis () const final
 
bool hasAbilityToProduceInEndRuns () const final
 

Static Public Member Functions

static void fillDescriptions (edm::ConfigurationDescriptions &descriptions)
 

Private Member Functions

void assignToSubjets (const reco::GenParticleRefVector &clusteredParticles, const edm::Handle< edm::View< reco::Jet > > &subjets, const std::vector< int > &subjetIndices, std::vector< reco::GenParticleRefVector > &assignedParticles)
 
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)
 
void matchGroomedJets (const edm::Handle< edm::View< reco::Jet > > &jets, const edm::Handle< edm::View< reco::Jet > > &matchedJets, std::vector< int > &matchedIndices)
 
void matchReclusteredJets (const edm::Handle< edm::View< reco::Jet > > &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices)
 
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)
 
void produce (edm::Event &, const edm::EventSetup &) override
 
void setFlavours (const reco::GenParticleRefVector &clusteredbHadrons, const reco::GenParticleRefVector &clusteredcHadrons, const reco::GenParticleRefVector &clusteredPartons, int &hadronFlavour, int &partonFlavour)
 

Private Attributes

const edm::EDGetTokenT< reco::GenParticleRefVectorbHadronsToken_
 
const edm::EDGetTokenT< reco::GenParticleRefVectorcHadronsToken_
 
ClusterSequencePtr fjClusterSeq_
 
JetDefPtr fjJetDefinition_
 
const double ghostRescaling_
 
edm::EDGetTokenT< edm::View< reco::Jet > > groomedJetsToken_
 
const bool hadronFlavourHasPriority_
 
const std::string jetAlgorithm_
 
const double jetPtMin_
 
const edm::EDGetTokenT< edm::View< reco::Jet > > jetsToken_
 
edm::EDGetTokenT< reco::GenParticleRefVectorleptonsToken_
 
const edm::EDGetTokenT< reco::GenParticleRefVectorpartonsToken_
 
const double relPtTolerance_
 
const double rParam_
 
edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
 
const bool useLeptons_
 
const bool useSubjets_
 

Additional Inherited Members

- Public Types inherited from edm::stream::EDProducer<>
typedef CacheContexts< T... > CacheTypes
 
typedef CacheTypes::GlobalCache GlobalCache
 
typedef AbilityChecker< T... > HasAbility
 
typedef CacheTypes::LuminosityBlockCache LuminosityBlockCache
 
typedef LuminosityBlockContextT< LuminosityBlockCache, RunCache, GlobalCacheLuminosityBlockContext
 
typedef CacheTypes::LuminosityBlockSummaryCache LuminosityBlockSummaryCache
 
typedef CacheTypes::RunCache RunCache
 
typedef RunContextT< RunCache, GlobalCacheRunContext
 
typedef CacheTypes::RunSummaryCache RunSummaryCache
 

Detailed Description

Clusters hadrons, partons, and jet contituents to determine the jet flavour.

This producer clusters hadrons, partons and jet contituents to determine the jet flavour. The jet flavour information is stored in the event as an AssociationVector which associates an object of type JetFlavourInfo to each of the jets.

The producer takes as input jets and hadron and partons selected by the HadronAndPartonSelector producer. The hadron and parton four-momenta are rescaled by a very small number (default rescale factor is 10e-18) which turns them into the so-called "ghosts". The "ghost" hadrons and partons are clustered together with all of the jet constituents. It is important to use the same clustering algorithm and jet size as for the original input jet collection. Since the "ghost" hadrons and partons are extremely soft, the resulting jet collection will be practically identical to the original one but now with "ghost" hadrons and partons clustered inside jets. The jet flavour is determined based on the "ghost" hadrons clustered inside a jet:

To further assign a more specific flavour to light-flavour jets, "ghost" partons are used:

In rare instances a conflict between the hadron- and parton-based flavours can occur. In such cases it is possible to keep both flavours or to give priority to the hadron-based flavour. This is controlled by the 'hadronFlavourHasPriority' switch. The priority is given to the hadron-based flavour as follows:

The producer is also capable of assigning the flavour to subjets of fat jets, in which case it produces an additional AssociationVector providing the flavour information for subjets. In order to assign the flavour to subjets, three input jet collections are required:

The "ghost" hadrons and partons clustered inside a fat jet are assigned to the closest subjet in the rapidity-phi space. Once hadrons and partons have been assigned to subjets, the subjet flavour is determined in the same way as for jets. The reason for requiring three jet collections as input in order to determine the subjet flavour is to avoid possible inconsistencies between the fat jet and subjet flavours (such as a non-b fat jet having a b subjet and vice versa) as well as the fact that re-clustering the constituents of groomed fat jets will generally result in a jet collection different from the input groomed fat jets. Also note that "ghost" particles generally cannot be clustered inside subjets in the same way this is done for fat jets. This is because some of the jet grooming techniques could reject such very soft particle. So instead, the "ghost" particles are assigned to the closest subjet.

Finally, "ghost" leptons can also be clustered inside jets but they are not used in any way to determine the jet flavour. This functionality is optional and is potentially useful to identify jets from hadronic taus.

For more details, please refer to https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagMCTools

Definition at line 143 of file JetFlavourClustering.cc.

Constructor & Destructor Documentation

JetFlavourClustering::JetFlavourClustering ( const edm::ParameterSet iConfig)
explicit

Definition at line 212 of file JetFlavourClustering.cc.

References Exception, fjJetDefinition_, edm::ParameterSet::getParameter(), groomedJetsToken_, jetAlgorithm_, leptonsToken_, rParam_, subjetsToken_, useLeptons_, and useSubjets_.

213  :
214 
215  jetsToken_(consumes<edm::View<reco::Jet> >(iConfig.getParameter<edm::InputTag>("jets"))),
216  bHadronsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("bHadrons"))),
217  cHadronsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("cHadrons"))),
218  partonsToken_(consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("partons"))),
219  jetAlgorithm_(iConfig.getParameter<std::string>("jetAlgorithm")),
220  rParam_(iConfig.getParameter<double>("rParam")),
221  jetPtMin_(
222  0.), // hardcoded to 0. since we simply want to recluster all input jets which already had some PtMin applied
223  ghostRescaling_(iConfig.exists("ghostRescaling") ? iConfig.getParameter<double>("ghostRescaling") : 1e-18),
225  iConfig.exists("relPtTolerance")
226  ? iConfig.getParameter<double>("relPtTolerance")
227  : 1e-03), // 0.1% relative difference in Pt should be sufficient to detect possible misconfigurations
228  hadronFlavourHasPriority_(iConfig.getParameter<bool>("hadronFlavourHasPriority")),
229  useSubjets_(iConfig.exists("groomedJets") && iConfig.exists("subjets")),
230  useLeptons_(iConfig.exists("leptons"))
231 
232 {
233  // register your products
234  produces<reco::JetFlavourInfoMatchingCollection>();
235  if (useSubjets_)
236  produces<reco::JetFlavourInfoMatchingCollection>("SubJets");
237 
238  // set jet algorithm
239  if (jetAlgorithm_ == "Kt")
240  fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::kt_algorithm, rParam_);
241  else if (jetAlgorithm_ == "CambridgeAachen")
242  fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::cambridge_algorithm, rParam_);
243  else if (jetAlgorithm_ == "AntiKt")
244  fjJetDefinition_ = std::make_shared<fastjet::JetDefinition>(fastjet::antikt_algorithm, rParam_);
245  else
246  throw cms::Exception("InvalidJetAlgorithm") << "Jet clustering algorithm is invalid: " << jetAlgorithm_
247  << ", use CambridgeAachen | Kt | AntiKt" << std::endl;
248 
249  if (useSubjets_) {
250  groomedJetsToken_ = consumes<edm::View<reco::Jet> >(iConfig.getParameter<edm::InputTag>("groomedJets"));
251  subjetsToken_ = consumes<edm::View<reco::Jet> >(iConfig.getParameter<edm::InputTag>("subjets"));
252  }
253  if (useLeptons_) {
254  leptonsToken_ = consumes<reco::GenParticleRefVector>(iConfig.getParameter<edm::InputTag>("leptons"));
255  }
256 }
edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
T getParameter(std::string const &) const
edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
bool exists(std::string const &parameterName) const
checks if a parameter exists
const edm::EDGetTokenT< reco::GenParticleRefVector > bHadronsToken_
const edm::EDGetTokenT< reco::GenParticleRefVector > partonsToken_
const edm::EDGetTokenT< reco::GenParticleRefVector > cHadronsToken_
const std::string jetAlgorithm_
const edm::EDGetTokenT< edm::View< reco::Jet > > jetsToken_
edm::EDGetTokenT< edm::View< reco::Jet > > groomedJetsToken_
JetFlavourClustering::~JetFlavourClustering ( )
override

Definition at line 258 of file JetFlavourClustering.cc.

258  {
259  // do anything here that needs to be done at desctruction time
260  // (e.g. close files, deallocate resources etc.)
261 }

Member Function Documentation

void JetFlavourClustering::assignToSubjets ( const reco::GenParticleRefVector clusteredParticles,
const edm::Handle< edm::View< reco::Jet > > &  subjets,
const std::vector< int > &  subjetIndices,
std::vector< reco::GenParticleRefVector > &  assignedParticles 
)
private

Definition at line 713 of file JetFlavourClustering.cc.

References edm::RefVector< C, T, F >::begin(), reco::deltaR2(), HLT_2018_cff::distance, edm::RefVector< C, T, F >::end(), and phi.

Referenced by produce().

716  {
717  // loop over clustered particles and assign them to different subjets based on smallest dR
718  for (reco::GenParticleRefVector::const_iterator it = clusteredParticles.begin(); it != clusteredParticles.end();
719  ++it) {
720  std::vector<double> dR2toSubjets;
721 
722  for (size_t sj = 0; sj < subjetIndices.size(); ++sj)
723  dR2toSubjets.push_back(reco::deltaR2((*it)->rapidity(),
724  (*it)->phi(),
725  subjets->at(subjetIndices.at(sj)).rapidity(),
726  subjets->at(subjetIndices.at(sj)).phi()));
727 
728  // find the closest subjet
729  int closestSubjetIdx =
730  std::distance(dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()));
731 
732  assignedParticles.at(closestSubjetIdx).push_back(*it);
733  }
734 }
const_iterator end() const
Termination of iteration.
Definition: RefVector.h:228
const_iterator begin() const
Initialize an iterator over the RefVector.
Definition: RefVector.h:223
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
void JetFlavourClustering::fillDescriptions ( edm::ConfigurationDescriptions descriptions)
static

Definition at line 737 of file JetFlavourClustering.cc.

References edm::ConfigurationDescriptions::addDefault(), DEFINE_FWK_MODULE, and edm::ParameterSetDescription::setUnknown().

737  {
738  //The following says we do not know what parameters are allowed so do no validation
739  // Please change this to state exactly what you do use, even if it is no parameters
741  desc.setUnknown();
742  descriptions.addDefault(desc);
743 }
void addDefault(ParameterSetDescription const &psetDescription)
void JetFlavourClustering::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 
)
private

Definition at line 520 of file JetFlavourClustering.cc.

References edm::RefVector< C, T, F >::begin(), edm::RefVector< C, T, F >::end(), AK4PFJetsMCFlavourInfos_cfi::ghostRescaling, and AlCaHLTBitMon_ParallelJobs::p.

Referenced by produce().

526  {
527  // insert "ghost" particles in the vector of jet constituents
528  for (reco::GenParticleRefVector::const_iterator it = particles->begin(); it != particles->end(); ++it) {
529  if ((*it)->pt() == 0) {
530  edm::LogInfo("NullTransverseMomentum") << "dropping input ghost candidate with pt=0";
531  continue;
532  }
533  fastjet::PseudoJet p((*it)->px(), (*it)->py(), (*it)->pz(), (*it)->energy());
534  p *= ghostRescaling; // rescale particle momentum
535  p.set_user_info(new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
536  constituents.push_back(p);
537  }
538 }
bool isLepton(const Candidate &part)
Definition: pdgIdUtils.h:13
const_iterator end() const
Termination of iteration.
Definition: RefVector.h:228
const_iterator begin() const
Initialize an iterator over the RefVector.
Definition: RefVector.h:223
bool isParton(const reco::Candidate &c)
Definition: CandMCTag.cc:46
void JetFlavourClustering::matchGroomedJets ( const edm::Handle< edm::View< reco::Jet > > &  jets,
const edm::Handle< edm::View< reco::Jet > > &  matchedJets,
std::vector< int > &  matchedIndices 
)
private

Definition at line 582 of file JetFlavourClustering.cc.

References reco::deltaR2(), HLT_2018_cff::distance, spr::find(), dqmiolumiharvest::j, singleTopDQM_cfi::jets, rParam_, and mathSSE::sqrt().

Referenced by produce().

584  {
585  std::vector<bool> jetLocks(jets->size(), false);
586  std::vector<int> jetIndices;
587 
588  for (size_t gj = 0; gj < groomedJets->size(); ++gj) {
589  double matchedDR2 = 1e9;
590  int matchedIdx = -1;
591 
592  if (groomedJets->at(gj).pt() > 0.) // skip pathological cases of groomed jets with Pt=0
593  {
594  for (size_t j = 0; j < jets->size(); ++j) {
595  if (jetLocks.at(j))
596  continue; // skip jets that have already been matched
597 
598  double tempDR2 = reco::deltaR2(
599  jets->at(j).rapidity(), jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi());
600  if (tempDR2 < matchedDR2) {
601  matchedDR2 = tempDR2;
602  matchedIdx = j;
603  }
604  }
605  }
606 
607  if (matchedIdx >= 0) {
608  if (matchedDR2 > rParam_ * rParam_) {
609  edm::LogWarning("MatchedJetsFarApart")
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_
612  << ".\n"
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.";
615  matchedIdx = -1;
616  } else
617  jetLocks.at(matchedIdx) = true;
618  }
619  jetIndices.push_back(matchedIdx);
620  }
621 
622  for (size_t j = 0; j < jets->size(); ++j) {
623  std::vector<int>::iterator matchedIndex = std::find(jetIndices.begin(), jetIndices.end(), j);
624 
625  matchedIndices.push_back(matchedIndex != jetIndices.end() ? std::distance(jetIndices.begin(), matchedIndex) : -1);
626  }
627 }
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
T sqrt(T t)
Definition: SSEVec.h:19
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
void JetFlavourClustering::matchReclusteredJets ( const edm::Handle< edm::View< reco::Jet > > &  jets,
const std::vector< fastjet::PseudoJet > &  matchedJets,
std::vector< int > &  matchedIndices 
)
private

Definition at line 541 of file JetFlavourClustering.cc.

References reco::deltaR2(), dqmiolumiharvest::j, singleTopDQM_cfi::jets, rParam_, and mathSSE::sqrt().

Referenced by produce().

543  {
544  std::vector<bool> matchedLocks(reclusteredJets.size(), false);
545 
546  for (size_t j = 0; j < jets->size(); ++j) {
547  double matchedDR2 = 1e9;
548  int matchedIdx = -1;
549 
550  for (size_t rj = 0; rj < reclusteredJets.size(); ++rj) {
551  if (matchedLocks.at(rj))
552  continue; // skip jets that have already been matched
553 
554  double tempDR2 = reco::deltaR2(jets->at(j).rapidity(),
555  jets->at(j).phi(),
556  reclusteredJets.at(rj).rapidity(),
557  reclusteredJets.at(rj).phi_std());
558  if (tempDR2 < matchedDR2) {
559  matchedDR2 = tempDR2;
560  matchedIdx = rj;
561  }
562  }
563 
564  if (matchedIdx >= 0) {
565  if (matchedDR2 > rParam_ * rParam_) {
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.";
571  } else
572  matchedLocks.at(matchedIdx) = true;
573  } else
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.";
576 
577  matchedIndices.push_back(matchedIdx);
578  }
579 }
T sqrt(T t)
Definition: SSEVec.h:19
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
void JetFlavourClustering::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 
)
private

Definition at line 630 of file JetFlavourClustering.cc.

References g, and alignCSCRings::s.

Referenced by produce().

633  {
634  for (size_t g = 0; g < groomedIndices.size(); ++g) {
635  std::vector<int> subjetIndices;
636 
637  if (groomedIndices.at(g) >= 0) {
638  for (size_t s = 0; s < groomedJets->at(groomedIndices.at(g)).numberOfDaughters(); ++s) {
639  const edm::Ptr<reco::Candidate>& subjet = groomedJets->at(groomedIndices.at(g)).daughterPtr(s);
640 
641  for (size_t sj = 0; sj < subjets->size(); ++sj) {
642  if (subjet == edm::Ptr<reco::Candidate>(subjets->ptrAt(sj))) {
643  subjetIndices.push_back(sj);
644  break;
645  }
646  }
647  }
648 
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.";
652 
653  matchedIndices.push_back(subjetIndices);
654  } else
655  matchedIndices.push_back(subjetIndices);
656  }
657 }
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
Definition: Activities.doc:4
void JetFlavourClustering::produce ( edm::Event iEvent,
const edm::EventSetup iSetup 
)
overrideprivate

Definition at line 268 of file JetFlavourClustering.cc.

References funct::abs(), assignToSubjets(), AK4GenJetFlavourInfos_cfi::bHadrons, bHadronsToken_, AK4GenJetFlavourInfos_cfi::cHadrons, cHadronsToken_, fjClusterSeq_, fjJetDefinition_, edm::Event::getByToken(), ghostRescaling_, groomedJetsToken_, jets_cff::hadronFlavour, mps_fire::i, insertGhosts(), edm::Ptr< T >::isAvailable(), GhostInfo::isbHadron(), GhostInfo::isHadron(), GhostInfo::isLepton(), edm::Ptr< T >::isNonnull(), GhostInfo::isParton(), GenHFHadronMatcher_cfi::jetFlavourInfos, jetPtMin_, singleTopDQM_cfi::jets, jetsToken_, HLT_2018_cff::leptons, leptonsToken_, visualization-live-secondInstance_cfg::m, matchGroomedJets(), matchReclusteredJets(), matchSubjets(), eostools::move(), GhostInfo::particleRef(), jets_cff::partonFlavour, dqmAnalyzer_cff::partons, partonsToken_, DiDispStaMuonMonitor_cfi::pt, edm::RefVector< C, T, F >::push_back(), edm::Event::put(), relPtTolerance_, setFlavours(), edm::RefVector< C, T, F >::size(), subjetsToken_, useLeptons_, and useSubjets_.

268  {
270  iEvent.getByToken(jetsToken_, jets);
271 
272  edm::Handle<edm::View<reco::Jet> > groomedJets;
274  if (useSubjets_) {
275  iEvent.getByToken(groomedJetsToken_, groomedJets);
276  iEvent.getByToken(subjetsToken_, subjets);
277  }
278 
280  iEvent.getByToken(bHadronsToken_, bHadrons);
281 
283  iEvent.getByToken(cHadronsToken_, cHadrons);
284 
286  iEvent.getByToken(partonsToken_, partons);
287 
289  if (useLeptons_)
290  iEvent.getByToken(leptonsToken_, leptons);
291 
292  auto jetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(reco::JetRefBaseProd(jets));
293  std::unique_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
294  if (useSubjets_)
295  subjetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(reco::JetRefBaseProd(subjets));
296 
297  // vector of constituents for reclustering jets and "ghosts"
298  std::vector<fastjet::PseudoJet> fjInputs;
299  unsigned int reserve = jets->size() * 128 + bHadrons->size() + cHadrons->size() + partons->size();
300  if (useLeptons_)
301  reserve += leptons->size();
302  fjInputs.reserve(reserve);
303  // loop over all input jets and collect all their constituents
304  for (edm::View<reco::Jet>::const_iterator it = jets->begin(); it != jets->end(); ++it) {
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) {
308  reco::CandidatePtr constit = *m;
309  if (!constit.isNonnull() || !constit.isAvailable()) {
310  edm::LogError("MissingJetConstituent") << "Jet constituent required for jet reclustering is missing. "
311  "Reclustered jets are not guaranteed to reproduce the original jets!";
312  continue;
313  }
314  if (constit->pt() == 0) {
315  edm::LogWarning("NullTransverseMomentum") << "dropping input candidate with pt=0";
316  continue;
317  }
318  fjInputs.push_back(fastjet::PseudoJet(constit->px(), constit->py(), constit->pz(), constit->energy()));
319  }
320  }
321  // insert "ghost" b hadrons in the vector of constituents
322  insertGhosts(bHadrons, ghostRescaling_, true, true, false, false, fjInputs);
323  // insert "ghost" c hadrons in the vector of constituents
324  insertGhosts(cHadrons, ghostRescaling_, true, false, false, false, fjInputs);
325  // insert "ghost" partons in the vector of constituents
326  insertGhosts(partons, ghostRescaling_, false, false, true, false, fjInputs);
327  // if used, insert "ghost" leptons in the vector of constituents
328  if (useLeptons_)
329  insertGhosts(leptons, ghostRescaling_, false, false, false, true, fjInputs);
330 
331  // define jet clustering sequence
332  fjClusterSeq_ = std::make_shared<fastjet::ClusterSequence>(fjInputs, *fjJetDefinition_);
333  // recluster jet constituents and inserted "ghosts"
334  std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(fjClusterSeq_->inclusive_jets(jetPtMin_));
335 
336  if (inclusiveJets.size() < jets->size())
337  edm::LogError("TooFewReclusteredJets")
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.";
340 
341  // match reclustered and original jets
342  std::vector<int> reclusteredIndices;
343  matchReclusteredJets(jets, inclusiveJets, reclusteredIndices);
344 
345  // match groomed and original jets
346  std::vector<int> groomedIndices;
347  if (useSubjets_) {
348  if (groomedJets->size() > jets->size())
349  edm::LogError("TooManyGroomedJets")
350  << "There are more groomed (" << groomedJets->size() << ") than original jets (" << jets->size()
351  << "). Please check that the two jet collections belong to each other.";
352 
353  matchGroomedJets(jets, groomedJets, groomedIndices);
354  }
355 
356  // match subjets and original jets
357  std::vector<std::vector<int> > subjetIndices;
358  if (useSubjets_) {
359  matchSubjets(groomedIndices, groomedJets, subjets, subjetIndices);
360  }
361 
362  // determine jet flavour
363  for (size_t i = 0; i < jets->size(); ++i) {
364  reco::GenParticleRefVector clusteredbHadrons;
365  reco::GenParticleRefVector clusteredcHadrons;
366  reco::GenParticleRefVector clusteredPartons;
367  reco::GenParticleRefVector clusteredLeptons;
368 
369  // if matching reclustered to original jets failed
370  if (reclusteredIndices.at(i) < 0) {
371  // set an empty JetFlavourInfo for this jet
372  (*jetFlavourInfos)[jets->refAt(i)] =
373  reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
374  } else if (jets->at(i).pt() == 0) {
375  edm::LogWarning("NullTransverseMomentum")
376  << "The original jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
377 
378  // set an empty JetFlavourInfo for this jet
379  (*jetFlavourInfos)[jets->refAt(i)] =
380  reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
381 
382  // if subjets are used
383  if (useSubjets_ && !subjetIndices.at(i).empty()) {
384  // loop over subjets
385  for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj) {
386  // set an empty JetFlavourInfo for this subjet
387  (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] =
392  0,
393  0);
394  }
395  }
396  } else {
397  // since the "ghosts" are extremely soft, the configuration and ordering of the reclustered and original jets should in principle stay the same
398  if ((std::abs(inclusiveJets.at(reclusteredIndices.at(i)).pt() - jets->at(i).pt()) / jets->at(i).pt()) >
399  relPtTolerance_) {
400  if (jets->at(i).pt() < 10.) // special handling for low-Pt jets (Pt<10 GeV)
401  edm::LogWarning("JetPtMismatchAtLowPt")
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 "
411  "same job.";
412  else
413  edm::LogError("JetPtMismatch")
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 "
422  "same job.";
423  }
424 
425  // get jet constituents (sorted by Pt)
426  std::vector<fastjet::PseudoJet> constituents =
427  fastjet::sorted_by_pt(inclusiveJets.at(reclusteredIndices.at(i)).constituents());
428 
429  // loop over jet constituents and try to find "ghosts"
430  for (std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it) {
431  if (!it->has_user_info())
432  continue; // skip if not a "ghost"
433 
434  // "ghost" hadron
435  if (it->user_info<GhostInfo>().isHadron()) {
436  // "ghost" b hadron
437  if (it->user_info<GhostInfo>().isbHadron())
438  clusteredbHadrons.push_back(it->user_info<GhostInfo>().particleRef());
439  // "ghost" c hadron
440  else
441  clusteredcHadrons.push_back(it->user_info<GhostInfo>().particleRef());
442  }
443  // "ghost" parton
444  else if (it->user_info<GhostInfo>().isParton())
445  clusteredPartons.push_back(it->user_info<GhostInfo>().particleRef());
446  // "ghost" lepton
447  else if (it->user_info<GhostInfo>().isLepton())
448  clusteredLeptons.push_back(it->user_info<GhostInfo>().particleRef());
449  }
450 
451  int hadronFlavour = 0; // default hadron flavour set to 0 (= undefined)
452  int partonFlavour = 0; // default parton flavour set to 0 (= undefined)
453 
454  // set hadron- and parton-based flavours
455  setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
456 
457  // set the JetFlavourInfo for this jet
458  (*jetFlavourInfos)[jets->refAt(i)] = reco::JetFlavourInfo(
459  clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
460  }
461 
462  // if subjets are used, determine their flavour
463  if (useSubjets_) {
464  if (subjetIndices.at(i).empty())
465  continue; // continue if the original jet does not have subjets assigned
466 
467  // define vectors of GenParticleRefVectors for hadrons and partons assigned to different subjets
468  std::vector<reco::GenParticleRefVector> assignedbHadrons(subjetIndices.at(i).size(),
470  std::vector<reco::GenParticleRefVector> assignedcHadrons(subjetIndices.at(i).size(),
472  std::vector<reco::GenParticleRefVector> assignedPartons(subjetIndices.at(i).size(), reco::GenParticleRefVector());
473  std::vector<reco::GenParticleRefVector> assignedLeptons(subjetIndices.at(i).size(), reco::GenParticleRefVector());
474 
475  // loop over clustered b hadrons and assign them to different subjets based on smallest dR
476  assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(i), assignedbHadrons);
477  // loop over clustered c hadrons and assign them to different subjets based on smallest dR
478  assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(i), assignedcHadrons);
479  // loop over clustered partons and assign them to different subjets based on smallest dR
480  assignToSubjets(clusteredPartons, subjets, subjetIndices.at(i), assignedPartons);
481  // if used, loop over clustered leptons and assign them to different subjets based on smallest dR
482  if (useLeptons_)
483  assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(i), assignedLeptons);
484 
485  // loop over subjets and determine their flavour
486  for (size_t sj = 0; sj < subjetIndices.at(i).size(); ++sj) {
487  int subjetHadronFlavour = 0; // default hadron flavour set to 0 (= undefined)
488  int subjetPartonFlavour = 0; // default parton flavour set to 0 (= undefined)
489 
490  // set hadron- and parton-based flavours
491  setFlavours(assignedbHadrons.at(sj),
492  assignedcHadrons.at(sj),
493  assignedPartons.at(sj),
494  subjetHadronFlavour,
495  subjetPartonFlavour);
496 
497  // set the JetFlavourInfo for this subjet
498  (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] =
499  reco::JetFlavourInfo(assignedbHadrons.at(sj),
500  assignedcHadrons.at(sj),
501  assignedPartons.at(sj),
502  assignedLeptons.at(sj),
503  subjetHadronFlavour,
504  subjetPartonFlavour);
505  }
506  }
507  }
508 
509  //deallocate only at the end of the event processing
510  fjClusterSeq_.reset();
511 
512  // put jet flavour infos in the event
513  iEvent.put(std::move(jetFlavourInfos));
514  // put subjet flavour infos in the event
515  if (useSubjets_)
516  iEvent.put(std::move(subjetFlavourInfos), "SubJets");
517 }
const reco::GenParticleRef & particleRef() const
edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:131
void assignToSubjets(const reco::GenParticleRefVector &clusteredParticles, const edm::Handle< edm::View< reco::Jet > > &subjets, const std::vector< int > &subjetIndices, std::vector< reco::GenParticleRefVector > &assignedParticles)
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:525
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)
edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
bool isAvailable() const
Definition: Ptr.h:229
void setFlavours(const reco::GenParticleRefVector &clusteredbHadrons, const reco::GenParticleRefVector &clusteredcHadrons, const reco::GenParticleRefVector &clusteredPartons, int &hadronFlavour, int &partonFlavour)
const edm::EDGetTokenT< reco::GenParticleRefVector > bHadronsToken_
void matchGroomedJets(const edm::Handle< edm::View< reco::Jet > > &jets, const edm::Handle< edm::View< reco::Jet > > &matchedJets, std::vector< int > &matchedIndices)
const edm::EDGetTokenT< reco::GenParticleRefVector > partonsToken_
const bool isParton() const
const bool isLepton() const
edm::RefToBaseProd< reco::Jet > JetRefBaseProd
Definition: JetCollection.h:13
const edm::EDGetTokenT< reco::GenParticleRefVector > cHadronsToken_
Class storing the jet flavour information.
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:146
void matchReclusteredJets(const edm::Handle< edm::View< reco::Jet > > &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices)
edm::RefVector< GenParticleCollection > GenParticleRefVector
vector of reference to GenParticle in the same collection
const edm::EDGetTokenT< edm::View< reco::Jet > > jetsToken_
hadronFlavour
Definition: jets_cff.py:476
boost::indirect_iterator< typename seq_t::const_iterator > const_iterator
Definition: View.h:86
partonFlavour
Definition: jets_cff.py:475
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.
Definition: RefVector.h:67
size_type size() const
Size of the RefVector.
Definition: RefVector.h:102
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_
def move(src, dest)
Definition: eostools.py:511
void JetFlavourClustering::setFlavours ( const reco::GenParticleRefVector clusteredbHadrons,
const reco::GenParticleRefVector clusteredcHadrons,
const reco::GenParticleRefVector clusteredPartons,
int &  hadronFlavour,
int &  partonFlavour 
)
private

Definition at line 660 of file JetFlavourClustering.cc.

References funct::abs(), edm::RefVector< C, T, F >::begin(), edm::RefVector< C, T, F >::empty(), edm::RefVector< C, T, F >::end(), jets_cff::hadronFlavour, hadronFlavourHasPriority_, CandMCTagUtils::isLightParton(), edm::Ref< C, T, F >::isNonnull(), and edm::Ref< C, T, F >::isNull().

Referenced by produce().

664  {
665  reco::GenParticleRef hardestParton;
666  reco::GenParticleRef hardestLightParton;
667  reco::GenParticleRef flavourParton;
668 
669  // loop over clustered partons (already sorted by Pt)
670  for (reco::GenParticleRefVector::const_iterator it = clusteredPartons.begin(); it != clusteredPartons.end(); ++it) {
671  // hardest parton
672  if (hardestParton.isNull())
673  hardestParton = (*it);
674  // hardest light-flavour parton
675  if (hardestLightParton.isNull()) {
676  if (CandMCTagUtils::isLightParton(*(*it)))
677  hardestLightParton = (*it);
678  }
679  // c flavour
680  if (flavourParton.isNull() && (std::abs((*it)->pdgId()) == 4))
681  flavourParton = (*it);
682  // b flavour gets priority
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);
688  }
689  }
690 
691  // set hadron-based flavour
692  if (!clusteredbHadrons.empty())
693  hadronFlavour = 5;
694  else if (!clusteredcHadrons.empty() && clusteredbHadrons.empty())
695  hadronFlavour = 4;
696  // set parton-based flavour
697  if (flavourParton.isNull()) {
698  if (hardestParton.isNonnull())
699  partonFlavour = hardestParton->pdgId();
700  } else
701  partonFlavour = flavourParton->pdgId();
702 
703  // if enabled, check for conflicts between hadron- and parton-based flavours and give priority to the hadron-based flavour
705  if (hadronFlavour == 0 && (std::abs(partonFlavour) == 4 || std::abs(partonFlavour) == 5))
706  partonFlavour = (hardestLightParton.isNonnull() ? hardestLightParton->pdgId() : 0);
707  else if (hadronFlavour != 0 && std::abs(partonFlavour) != hadronFlavour)
709  }
710 }
bool isLightParton(const reco::Candidate &c)
Definition: CandMCTag.cc:55
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
const_iterator end() const
Termination of iteration.
Definition: RefVector.h:228
bool empty() const
Is the RefVector empty.
Definition: RefVector.h:99
const_iterator begin() const
Initialize an iterator over the RefVector.
Definition: RefVector.h:223
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool isNull() const
Checks for null.
Definition: Ref.h:235
hadronFlavour
Definition: jets_cff.py:476
partonFlavour
Definition: jets_cff.py:475

Member Data Documentation

const edm::EDGetTokenT<reco::GenParticleRefVector> JetFlavourClustering::bHadronsToken_
private

Definition at line 187 of file JetFlavourClustering.cc.

Referenced by produce().

const edm::EDGetTokenT<reco::GenParticleRefVector> JetFlavourClustering::cHadronsToken_
private

Definition at line 188 of file JetFlavourClustering.cc.

Referenced by produce().

ClusterSequencePtr JetFlavourClustering::fjClusterSeq_
private

Definition at line 201 of file JetFlavourClustering.cc.

Referenced by produce().

JetDefPtr JetFlavourClustering::fjJetDefinition_
private

Definition at line 202 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().

const double JetFlavourClustering::ghostRescaling_
private

Definition at line 195 of file JetFlavourClustering.cc.

Referenced by produce().

edm::EDGetTokenT<edm::View<reco::Jet> > JetFlavourClustering::groomedJetsToken_
private

Definition at line 185 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().

const bool JetFlavourClustering::hadronFlavourHasPriority_
private

Definition at line 197 of file JetFlavourClustering.cc.

Referenced by setFlavours().

const std::string JetFlavourClustering::jetAlgorithm_
private

Definition at line 192 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering().

const double JetFlavourClustering::jetPtMin_
private

Definition at line 194 of file JetFlavourClustering.cc.

Referenced by produce().

const edm::EDGetTokenT<edm::View<reco::Jet> > JetFlavourClustering::jetsToken_
private

Definition at line 184 of file JetFlavourClustering.cc.

Referenced by produce().

edm::EDGetTokenT<reco::GenParticleRefVector> JetFlavourClustering::leptonsToken_
private

Definition at line 190 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().

const edm::EDGetTokenT<reco::GenParticleRefVector> JetFlavourClustering::partonsToken_
private

Definition at line 189 of file JetFlavourClustering.cc.

Referenced by produce().

const double JetFlavourClustering::relPtTolerance_
private

Definition at line 196 of file JetFlavourClustering.cc.

Referenced by produce().

const double JetFlavourClustering::rParam_
private
edm::EDGetTokenT<edm::View<reco::Jet> > JetFlavourClustering::subjetsToken_
private

Definition at line 186 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().

const bool JetFlavourClustering::useLeptons_
private

Definition at line 199 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().

const bool JetFlavourClustering::useSubjets_
private

Definition at line 198 of file JetFlavourClustering.cc.

Referenced by JetFlavourClustering(), and produce().