100 #include "fastjet/JetDefinition.hh" 101 #include "fastjet/ClusterSequence.hh" 102 #include "fastjet/Selector.hh" 103 #include "fastjet/PseudoJet.hh" 109 typedef boost::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;
300 std::vector<edm::Ptr<reco::Candidate> > constituents = it->getJetConstituents();
301 std::vector<edm::Ptr<reco::Candidate> >::const_iterator
m;
302 for( m = constituents.begin(); m != constituents.end(); ++
m )
306 edm::LogError(
"MissingJetConstituent") <<
"Jet constituent required for jet reclustering is missing. Reclustered jets are not guaranteed to reproduce the original jets!";
309 if(constit->pt() == 0)
311 edm::LogWarning(
"NullTransverseMomentum") <<
"dropping input candidate with pt=0";
314 fjInputs.push_back(fastjet::PseudoJet(constit->px(),constit->py(),constit->pz(),constit->energy()));
330 std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt(
fjClusterSeq_->inclusive_jets(
jetPtMin_) );
332 if( inclusiveJets.size() < jets->size() )
333 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.";
336 std::vector<int> reclusteredIndices;
340 std::vector<int> groomedIndices;
343 if( groomedJets->size() > jets->size() )
344 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.";
350 std::vector<std::vector<int> > subjetIndices;
353 matchSubjets(groomedIndices,groomedJets,subjets,subjetIndices);
357 for(
size_t i=0;
i<jets->size(); ++
i)
365 if( reclusteredIndices.at(
i) < 0 )
368 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
370 else if( jets->at(
i).pt() == 0 )
372 edm::LogWarning(
"NullTransverseMomentum") <<
"The original jet " <<
i <<
" has Pt=0. This is not expected so the jet will be skipped.";
375 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
381 for(
size_t sj=0; sj<subjetIndices.at(
i).size(); ++sj)
393 if( jets->at(
i).pt() < 10. )
394 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" 395 <<
"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" 396 <<
"Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n" 397 <<
"\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.";
399 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" 400 <<
"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" 401 <<
"\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.";
405 std::vector<fastjet::PseudoJet> constituents = fastjet::sorted_by_pt( inclusiveJets.at(reclusteredIndices.at(
i)).constituents() );
408 for(std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it)
410 if( !it->has_user_info() )
continue;
434 setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
437 (*jetFlavourInfos)[jets->refAt(
i)] =
reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
443 if( subjetIndices.at(
i).size()==0 )
continue;
452 assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(
i), assignedbHadrons);
454 assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(
i), assignedcHadrons);
456 assignToSubjets(clusteredPartons, subjets, subjetIndices.at(
i), assignedPartons);
459 assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(
i), assignedLeptons);
462 for(
size_t sj=0; sj<subjetIndices.at(
i).size(); ++sj)
464 int subjetHadronFlavour = 0;
465 int subjetPartonFlavour = 0;
468 setFlavours(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
471 (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(
i).at(sj))] =
reco::JetFlavourInfo(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), assignedLeptons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
487 const bool isHadron,
const bool isbHadron,
const bool isParton,
const bool isLepton,
488 std::vector<fastjet::PseudoJet>& constituents)
495 edm::LogInfo(
"NullTransverseMomentum") <<
"dropping input ghost candidate with pt=0";
498 fastjet::PseudoJet
p((*it)->px(),(*it)->py(),(*it)->pz(),(*it)->energy());
500 p.set_user_info(
new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
501 constituents.push_back(p);
508 const std::vector<fastjet::PseudoJet>& reclusteredJets,
509 std::vector<int>& matchedIndices)
511 std::vector<bool> matchedLocks(reclusteredJets.size(),
false);
513 for(
size_t j=0; j<
jets->size(); ++j)
515 double matchedDR2 = 1e9;
518 for(
size_t rj=0; rj<reclusteredJets.size(); ++rj)
520 if( matchedLocks.at(rj) )
continue;
522 double tempDR2 =
reco::deltaR2(
jets->at(j).rapidity(),
jets->at(j).phi(), reclusteredJets.at(rj).rapidity(), reclusteredJets.at(rj).phi_std() );
523 if( tempDR2 < matchedDR2 )
525 matchedDR2 = tempDR2;
534 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" 535 <<
"This is not expected so please check that the jet algorithm and jet size match those used for the original jet collection.";
538 matchedLocks.at(matchedIdx) =
true;
541 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.";
543 matchedIndices.push_back(matchedIdx);
551 std::vector<int>& matchedIndices)
553 std::vector<bool> jetLocks(
jets->size(),
false);
554 std::vector<int> jetIndices;
556 for(
size_t gj=0; gj<groomedJets->size(); ++gj)
558 double matchedDR2 = 1e9;
561 if( groomedJets->at(gj).pt()>0. )
563 for(
size_t j=0; j<
jets->size(); ++j)
565 if( jetLocks.at(j) )
continue;
567 double tempDR2 =
reco::deltaR2(
jets->at(j).rapidity(),
jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi() );
568 if( tempDR2 < matchedDR2 )
570 matchedDR2 = tempDR2;
580 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" 581 <<
"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.";
585 jetLocks.at(matchedIdx) =
true;
587 jetIndices.push_back(matchedIdx);
590 for(
size_t j=0; j<
jets->size(); ++j)
592 std::vector<int>::iterator matchedIndex =
std::find( jetIndices.begin(), jetIndices.end(), j );
594 matchedIndices.push_back( matchedIndex != jetIndices.end() ?
std::distance(jetIndices.begin(),matchedIndex) : -1 );
603 std::vector<std::vector<int> >& matchedIndices)
605 for(
size_t g=0;
g<groomedIndices.size(); ++
g)
607 std::vector<int> subjetIndices;
609 if( groomedIndices.at(
g)>=0 )
611 for(
size_t s=0;
s<groomedJets->at(groomedIndices.at(
g)).numberOfDaughters(); ++
s)
615 for(
size_t sj=0; sj<subjets->size(); ++sj)
619 subjetIndices.push_back(sj);
625 if( subjetIndices.size() == 0 )
626 edm::LogError(
"SubjetMatchingFailed") <<
"Matching subjets to original jets failed. Please check that the groomed jet and subjet collections belong to each other.";
628 matchedIndices.push_back(subjetIndices);
631 matchedIndices.push_back(subjetIndices);
651 if( hardestParton.
isNull() )
652 hardestParton = (*it);
654 if( hardestLightParton.
isNull() )
657 hardestLightParton = (*it);
660 if( flavourParton.
isNull() && (
std::abs( (*it)->pdgId() ) == 4 ) )
661 flavourParton = (*it);
663 if(
std::abs( (*it)->pdgId() ) == 5 )
665 if( flavourParton.
isNull() )
666 flavourParton = (*it);
667 else if(
std::abs( flavourParton->pdgId() ) != 5 )
668 flavourParton = (*it);
673 if( clusteredbHadrons.
size()>0 )
675 else if( clusteredcHadrons.
size()>0 && clusteredbHadrons.
size()==0 )
678 if( flavourParton.
isNull() )
680 if( hardestParton.
isNonnull() ) partonFlavour = hardestParton->pdgId();
683 partonFlavour = flavourParton->pdgId();
688 if( hadronFlavour==0 && (
std::abs(partonFlavour)==4 ||
std::abs(partonFlavour)==5) )
689 partonFlavour = ( hardestLightParton.
isNonnull() ? hardestLightParton->pdgId() : 0 );
691 partonFlavour = hadronFlavour;
699 const std::vector<int>& subjetIndices,
700 std::vector<reco::GenParticleRefVector>& assignedParticles)
705 std::vector<double> dR2toSubjets;
707 for(
size_t sj=0; sj<subjetIndices.size(); ++sj)
708 dR2toSubjets.push_back(
reco::deltaR2( (*it)->rapidity(), (*it)->phi(), subjets->at(subjetIndices.at(sj)).rapidity(), subjets->at(subjetIndices.at(sj)).
phi() ) );
711 int closestSubjetIdx =
std::distance( dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()) );
713 assignedParticles.at(closestSubjetIdx).push_back( *it );
const reco::GenParticleRef & particleRef() const
edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
T getParameter(std::string const &) const
bool isLightParton(const reco::Candidate &c)
boost::shared_ptr< fastjet::JetDefinition > JetDefPtr
virtual void produce(edm::Event &, const edm::EventSetup &)
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
boost::shared_ptr< fastjet::ClusterSequence > ClusterSequencePtr
#define DEFINE_FWK_MODULE(type)
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)
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_
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
const edm::EDGetTokenT< edm::View< reco::Jet > > jetsToken_
bool isParton(const reco::Candidate &c)
T1 deltaR2(T1 eta1, T2 phi1, T3 eta2, T4 phi2)
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_