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{
124 if( isHadron )
m_type |= ( 1 << 0 );
125 if( isbHadron )
m_type |= ( 1 << 1 );
126 if( isParton )
m_type |= ( 1 << 2 );
127 if( isLepton )
m_type |= ( 1 << 3 );
154 std::vector<fastjet::PseudoJet>& constituents);
157 const std::vector<fastjet::PseudoJet>& matchedJets,
158 std::vector<int>& matchedIndices);
161 std::vector<int>& matchedIndices);
162 void matchSubjets(
const std::vector<int>& groomedIndices,
165 std::vector<std::vector<int> >& matchedIndices);
175 const std::vector<int>& subjetIndices,
176 std::vector<reco::GenParticleRefVector>& assignedParticles);
209 jetsToken_(consumes<
edm::
View<
reco::
Jet> >( iConfig.getParameter<
edm::InputTag>(
"jets")) ),
213 jetAlgorithm_(iConfig.getParameter<
std::
string>(
"jetAlgorithm")),
214 rParam_(iConfig.getParameter<double>(
"rParam")),
216 ghostRescaling_(iConfig.exists(
"ghostRescaling") ? iConfig.getParameter<double>(
"ghostRescaling") : 1
e-18),
217 relPtTolerance_(iConfig.exists(
"relPtTolerance") ? iConfig.getParameter<double>(
"relPtTolerance") : 1
e-03),
218 hadronFlavourHasPriority_(iConfig.getParameter<
bool>(
"hadronFlavourHasPriority")),
219 useSubjets_(iConfig.exists(
"groomedJets") && iConfig.exists(
"subjets")),
220 useLeptons_(iConfig.exists(
"leptons"))
224 produces<reco::JetFlavourInfoMatchingCollection>();
226 produces<reco::JetFlavourInfoMatchingCollection>(
"SubJets");
236 throw cms::Exception(
"InvalidJetAlgorithm") <<
"Jet clustering algorithm is invalid: " <<
jetAlgorithm_ <<
", use CambridgeAachen | Kt | AntiKt" << std::endl;
291 std::unique_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
293 subjetFlavourInfos = std::make_unique<reco::JetFlavourInfoMatchingCollection>(
reco::JetRefBaseProd(subjets));
296 std::vector<fastjet::PseudoJet> fjInputs;
297 unsigned int reserve = jets->size()*128 + bHadrons->
size() + cHadrons->
size() + partons->
size();
299 fjInputs.reserve(reserve);
303 std::vector<edm::Ptr<reco::Candidate> > constituents = it->getJetConstituents();
304 std::vector<edm::Ptr<reco::Candidate> >::const_iterator
m;
305 for( m = constituents.begin(); m != constituents.end(); ++
m )
309 edm::LogError(
"MissingJetConstituent") <<
"Jet constituent required for jet reclustering is missing. Reclustered jets are not guaranteed to reproduce the original jets!";
312 if(constit->pt() == 0)
314 edm::LogWarning(
"NullTransverseMomentum") <<
"dropping input candidate with pt=0";
317 fjInputs.push_back(fastjet::PseudoJet(constit->px(),constit->py(),constit->pz(),constit->energy()));
333 std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(
fjClusterSeq_->inclusive_jets(
jetPtMin_) );
335 if( inclusiveJets.size() < jets->size() )
336 edm::LogError(
"TooFewReclusteredJets") <<
"There are fewer reclustered (" << inclusiveJets.size() <<
") than original jets (" << jets->size() <<
"). Please check that the jet algorithm and jet size match those used for the original jet collection.";
339 std::vector<int> reclusteredIndices;
343 std::vector<int> groomedIndices;
346 if( groomedJets->size() > jets->size() )
347 edm::LogError(
"TooManyGroomedJets") <<
"There are more groomed (" << groomedJets->size() <<
") than original jets (" << jets->size() <<
"). Please check that the two jet collections belong to each other.";
353 std::vector<std::vector<int> > subjetIndices;
356 matchSubjets(groomedIndices,groomedJets,subjets,subjetIndices);
360 for(
size_t i=0;
i<jets->size(); ++
i)
368 if( reclusteredIndices.at(
i) < 0 )
371 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
373 else if( jets->at(
i).pt() == 0 )
375 edm::LogWarning(
"NullTransverseMomentum") <<
"The original jet " <<
i <<
" has Pt=0. This is not expected so the jet will be skipped.";
378 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
384 for(
size_t sj=0; sj<subjetIndices.at(
i).size(); ++sj)
396 if( jets->at(
i).pt() < 10. )
397 edm::LogWarning(
"JetPtMismatchAtLowPt") <<
"The reclustered and original jet " <<
i <<
" have different Pt's (" << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " << jets->at(
i).pt() <<
" GeV, respectively).\n" 398 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection and also make sure the original jets are uncorrected. In addition, make sure you are not using CaloJets which are presently not supported.\n" 399 <<
"Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n" 400 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision in which case make sure the original jet collection is produced and reclustering is performed in the same job.";
402 edm::LogError(
"JetPtMismatch") <<
"The reclustered and original jet " <<
i <<
" have different Pt's (" << inclusiveJets.at(reclusteredIndices.at(
i)).
pt() <<
" vs " << jets->at(
i).pt() <<
" GeV, respectively).\n" 403 <<
"Please check that the jet algorithm and jet size match those used for the original jet collection and also make sure the original jets are uncorrected. In addition, make sure you are not using CaloJets which are presently not supported.\n" 404 <<
"\nIn extremely rare instances the mismatch could be caused by a difference in the machine precision in which case make sure the original jet collection is produced and reclustering is performed in the same job.";
408 std::vector<fastjet::PseudoJet> constituents = fastjet::sorted_by_pt( inclusiveJets.at(reclusteredIndices.at(
i)).constituents() );
411 for(std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it)
413 if( !it->has_user_info() )
continue;
437 setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
440 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
446 if( subjetIndices.at(
i).empty() )
continue;
455 assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(
i), assignedbHadrons);
457 assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(
i), assignedcHadrons);
459 assignToSubjets(clusteredPartons, subjets, subjetIndices.at(
i), assignedPartons);
462 assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(
i), assignedLeptons);
465 for(
size_t sj=0; sj<subjetIndices.at(
i).size(); ++sj)
467 int subjetHadronFlavour = 0;
468 int subjetPartonFlavour = 0;
471 setFlavours(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
474 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
reco::JetFlavourInfo(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), assignedLeptons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
493 const bool isHadron,
const bool isbHadron,
const bool isParton,
const bool isLepton,
494 std::vector<fastjet::PseudoJet>& constituents)
501 edm::LogInfo(
"NullTransverseMomentum") <<
"dropping input ghost candidate with pt=0";
504 fastjet::PseudoJet
p((*it)->px(),(*it)->py(),(*it)->pz(),(*it)->energy());
506 p.set_user_info(
new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
507 constituents.push_back(p);
514 const std::vector<fastjet::PseudoJet>& reclusteredJets,
515 std::vector<int>& matchedIndices)
517 std::vector<bool> matchedLocks(reclusteredJets.size(),
false);
519 for(
size_t j=0; j<
jets->size(); ++j)
521 double matchedDR2 = 1e9;
524 for(
size_t rj=0; rj<reclusteredJets.size(); ++rj)
526 if( matchedLocks.at(rj) )
continue;
528 double tempDR2 =
reco::deltaR2(
jets->at(j).rapidity(),
jets->at(j).phi(), reclusteredJets.at(rj).rapidity(), reclusteredJets.at(rj).phi_std() );
529 if( tempDR2 < matchedDR2 )
531 matchedDR2 = tempDR2;
540 edm::LogError(
"JetMatchingFailed") <<
"Matched reclustered jet " << matchedIdx <<
" and original jet " << j <<
" are separated by dR=" <<
sqrt(matchedDR2) <<
" which is greater than the jet size R=" << rParam_ <<
".\n" 541 <<
"This is not expected so please check that the jet algorithm and jet size match those used for the original jet collection.";
544 matchedLocks.at(matchedIdx) =
true;
547 edm::LogError(
"JetMatchingFailed") <<
"Matching reclustered to original jets failed. Please check that the jet algorithm and jet size match those used for the original jet collection.";
549 matchedIndices.push_back(matchedIdx);
557 std::vector<int>& matchedIndices)
559 std::vector<bool> jetLocks(
jets->size(),
false);
560 std::vector<int> jetIndices;
562 for(
size_t gj=0; gj<groomedJets->size(); ++gj)
564 double matchedDR2 = 1e9;
567 if( groomedJets->at(gj).pt()>0. )
569 for(
size_t j=0; j<
jets->size(); ++j)
571 if( jetLocks.at(j) )
continue;
573 double tempDR2 =
reco::deltaR2(
jets->at(j).rapidity(),
jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi() );
574 if( tempDR2 < matchedDR2 )
576 matchedDR2 = tempDR2;
586 edm::LogWarning(
"MatchedJetsFarApart") <<
"Matched groomed jet " << gj <<
" and original jet " << matchedIdx <<
" are separated by dR=" <<
sqrt(matchedDR2) <<
" which is greater than the jet size R=" << rParam_ <<
".\n" 587 <<
"This is not expected so the matching of these two jets has been discarded. Please check that the two jet collections belong to each other.";
591 jetLocks.at(matchedIdx) =
true;
593 jetIndices.push_back(matchedIdx);
596 for(
size_t j=0; j<
jets->size(); ++j)
598 std::vector<int>::iterator matchedIndex =
std::find( jetIndices.begin(), jetIndices.end(), j );
600 matchedIndices.push_back( matchedIndex != jetIndices.end() ?
std::distance(jetIndices.begin(),matchedIndex) : -1 );
609 std::vector<std::vector<int> >& matchedIndices)
611 for(
size_t g=0;
g<groomedIndices.size(); ++
g)
613 std::vector<int> subjetIndices;
615 if( groomedIndices.at(
g)>=0 )
617 for(
size_t s=0;
s<groomedJets->at(groomedIndices.at(
g)).numberOfDaughters(); ++
s)
621 for(
size_t sj=0; sj<subjets->size(); ++sj)
625 subjetIndices.push_back(sj);
631 if( subjetIndices.empty() )
632 edm::LogError(
"SubjetMatchingFailed") <<
"Matching subjets to original jets failed. Please check that the groomed jet and subjet collections belong to each other.";
634 matchedIndices.push_back(subjetIndices);
637 matchedIndices.push_back(subjetIndices);
657 if( hardestParton.
isNull() )
658 hardestParton = (*it);
660 if( hardestLightParton.
isNull() )
663 hardestLightParton = (*it);
666 if( flavourParton.
isNull() && (
std::abs( (*it)->pdgId() ) == 4 ) )
667 flavourParton = (*it);
669 if(
std::abs( (*it)->pdgId() ) == 5 )
671 if( flavourParton.
isNull() )
672 flavourParton = (*it);
673 else if(
std::abs( flavourParton->pdgId() ) != 5 )
674 flavourParton = (*it);
679 if( !clusteredbHadrons.
empty() )
681 else if( !clusteredcHadrons.
empty() && clusteredbHadrons.
empty() )
684 if( flavourParton.
isNull() )
686 if( hardestParton.
isNonnull() ) partonFlavour = hardestParton->pdgId();
689 partonFlavour = flavourParton->pdgId();
694 if( hadronFlavour==0 && (
std::abs(partonFlavour)==4 ||
std::abs(partonFlavour)==5) )
695 partonFlavour = ( hardestLightParton.
isNonnull() ? hardestLightParton->pdgId() : 0 );
697 partonFlavour = hadronFlavour;
705 const std::vector<int>& subjetIndices,
706 std::vector<reco::GenParticleRefVector>& assignedParticles)
711 std::vector<double> dR2toSubjets;
713 for(
size_t sj=0; sj<subjetIndices.size(); ++sj)
714 dR2toSubjets.push_back(
reco::deltaR2( (*it)->rapidity(), (*it)->phi(), subjets->at(subjetIndices.at(sj)).rapidity(), subjets->at(subjetIndices.at(sj)).
phi() ) );
717 int closestSubjetIdx =
std::distance( dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()) );
719 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