CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
JetFlavourClustering.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: JetFlavourClustering
4 // Class: JetFlavourClustering
5 //
70 //
71 // Original Author: Dinko Ferencek
72 // Created: Wed Nov 6 00:49:55 CET 2013
73 //
74 //
75 
76 
77 // system include files
78 #include <memory>
79 
80 // user include files
83 
86 
88 
97 
98 #include "fastjet/JetDefinition.hh"
99 #include "fastjet/ClusterSequence.hh"
100 #include "fastjet/Selector.hh"
101 #include "fastjet/PseudoJet.hh"
102 
103 //
104 // constants, enums and typedefs
105 //
106 typedef boost::shared_ptr<fastjet::ClusterSequence> ClusterSequencePtr;
107 typedef boost::shared_ptr<fastjet::JetDefinition> JetDefPtr;
108 
109 //
110 // class declaration
111 //
112 class GhostInfo : public fastjet::PseudoJet::UserInfoBase{
113  public:
114  GhostInfo(const bool & isHadron,
115  const bool & isbHadron,
116  const bool & isParton,
117  const bool & isLepton,
119  m_particleRef(particleRef)
120  {
121  m_type = 0;
122  if( isHadron ) m_type |= ( 1 << 0 );
123  if( isbHadron ) m_type |= ( 1 << 1 );
124  if( isParton ) m_type |= ( 1 << 2 );
125  if( isLepton ) m_type |= ( 1 << 3 );
126  }
127 
128  const bool isHadron() const { return ( m_type & (1 << 0) ); }
129  const bool isbHadron() const { return ( m_type & (1 << 1) ); }
130  const bool isParton() const { return ( m_type & (1 << 2) ); }
131  const bool isLepton() const { return ( m_type & (1 << 3) ); }
132  const reco::GenParticleRef & particleRef() const { return m_particleRef; }
133 
134  protected:
136  int m_type;
137 };
138 
140  public:
141  explicit JetFlavourClustering(const edm::ParameterSet&);
143 
144  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
145 
146  private:
147  virtual void beginJob() ;
148  virtual void produce(edm::Event&, const edm::EventSetup&);
149  virtual void endJob() ;
150 
151  virtual void beginRun(edm::Run&, edm::EventSetup const&);
152  virtual void endRun(edm::Run&, edm::EventSetup const&);
155 
157  const double ghostRescaling,
158  const bool isHadron, const bool isbHadron, const bool isParton, const bool isLepton,
159  std::vector<fastjet::PseudoJet>& constituents);
160 
162  const std::vector<fastjet::PseudoJet>& matchedJets,
163  std::vector<int>& matchedIndices);
165  const edm::Handle<edm::View<reco::Jet> >& matchedJets,
166  std::vector<int>& matchedIndices);
167  void matchSubjets(const std::vector<int>& groomedIndices,
168  const edm::Handle<edm::View<reco::Jet> >& groomedJets,
169  const edm::Handle<edm::View<reco::Jet> >& subjets,
170  std::vector<std::vector<int> >& matchedIndices);
171 
172  void setFlavours(const reco::GenParticleRefVector& clusteredbHadrons,
173  const reco::GenParticleRefVector& clusteredcHadrons,
174  const reco::GenParticleRefVector& clusteredPartons,
175  int& hadronFlavour,
176  int& partonFlavour);
177 
178  void assignToSubjets(const reco::GenParticleRefVector& clusteredParticles,
179  const edm::Handle<edm::View<reco::Jet> >& subjets,
180  const std::vector<int>& subjetIndices,
181  std::vector<reco::GenParticleRefVector>& assignedParticles);
182 
183  // ----------member data ---------------------------
184  const edm::EDGetTokenT<edm::View<reco::Jet> > jetsToken_; // Input jet collection
185  const edm::EDGetTokenT<edm::View<reco::Jet> > groomedJetsToken_; // Input groomed jet collection
186  const edm::EDGetTokenT<edm::View<reco::Jet> > subjetsToken_; // Input subjet collection
191 
193  const double rParam_;
194  const double jetPtMin_;
195  const double ghostRescaling_;
196  const double relPtTolerance_;
198  const bool useSubjets_;
199  const bool useLeptons_;
200 
203 };
204 
205 //
206 // static data member definitions
207 //
208 
209 //
210 // constructors and destructor
211 //
213 
214  jetsToken_(consumes<edm::View<reco::Jet> >( iConfig.getParameter<edm::InputTag>("jets")) ),
215  groomedJetsToken_(mayConsume<edm::View<reco::Jet> >( iConfig.exists("groomedJets") ? iConfig.getParameter<edm::InputTag>("groomedJets") : edm::InputTag() )),
216  subjetsToken_(mayConsume<edm::View<reco::Jet> >( iConfig.exists("subjets") ? iConfig.getParameter<edm::InputTag>("subjets") : edm::InputTag() )),
217  bHadronsToken_(consumes<reco::GenParticleRefVector>( iConfig.getParameter<edm::InputTag>("bHadrons") )),
218  cHadronsToken_(consumes<reco::GenParticleRefVector>( iConfig.getParameter<edm::InputTag>("cHadrons") )),
219  partonsToken_(consumes<reco::GenParticleRefVector>( iConfig.getParameter<edm::InputTag>("partons") )),
220  leptonsToken_(mayConsume<reco::GenParticleRefVector>( iConfig.exists("leptons") ? iConfig.getParameter<edm::InputTag>("leptons") : edm::InputTag() )),
221  jetAlgorithm_(iConfig.getParameter<std::string>("jetAlgorithm")),
222  rParam_(iConfig.getParameter<double>("rParam")),
223  jetPtMin_(0.), // hardcoded to 0. since we simply want to recluster all input jets which already had some PtMin applied
224  ghostRescaling_(iConfig.exists("ghostRescaling") ? iConfig.getParameter<double>("ghostRescaling") : 1e-18),
225  relPtTolerance_(iConfig.exists("relPtTolerance") ? iConfig.getParameter<double>("relPtTolerance") : 1e-03), // 0.1% relative difference in Pt should be sufficient to detect possible misconfigurations
226  hadronFlavourHasPriority_(iConfig.getParameter<bool>("hadronFlavourHasPriority")),
227  useSubjets_(iConfig.exists("groomedJets") && iConfig.exists("subjets")),
228  useLeptons_(iConfig.exists("leptons"))
229 
230 {
231  // register your products
232  produces<reco::JetFlavourInfoMatchingCollection>();
233  if( useSubjets_ )
234  produces<reco::JetFlavourInfoMatchingCollection>("SubJets");
235 
236  // set jet algorithm
237  if (jetAlgorithm_=="Kt")
238  fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::kt_algorithm, rParam_) );
239  else if (jetAlgorithm_=="CambridgeAachen")
240  fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::cambridge_algorithm, rParam_) );
241  else if (jetAlgorithm_=="AntiKt")
242  fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::antikt_algorithm, rParam_) );
243  else
244  throw cms::Exception("InvalidJetAlgorithm") << "Jet clustering algorithm is invalid: " << jetAlgorithm_ << ", use CambridgeAachen | Kt | AntiKt" << std::endl;
245 }
246 
247 
249 {
250 
251  // do anything here that needs to be done at desctruction time
252  // (e.g. close files, deallocate resources etc.)
253 
254 }
255 
256 
257 //
258 // member functions
259 //
260 
261 // ------------ method called to produce the data ------------
262 void
264 {
266  iEvent.getByToken(jetsToken_, jets);
267 
268  edm::Handle<edm::View<reco::Jet> > groomedJets;
270  if( useSubjets_ )
271  {
272  iEvent.getByToken(groomedJetsToken_, groomedJets);
273  iEvent.getByToken(subjetsToken_, subjets);
274  }
275 
277  iEvent.getByToken(bHadronsToken_, bHadrons);
278 
280  iEvent.getByToken(cHadronsToken_, cHadrons);
281 
283  iEvent.getByToken(partonsToken_, partons);
284 
286  if( useLeptons_ )
287  iEvent.getByToken(leptonsToken_, leptons);
288 
289  std::auto_ptr<reco::JetFlavourInfoMatchingCollection> jetFlavourInfos( new reco::JetFlavourInfoMatchingCollection(reco::JetRefBaseProd(jets)) );
290  std::auto_ptr<reco::JetFlavourInfoMatchingCollection> subjetFlavourInfos;
291  if( useSubjets_ )
292  subjetFlavourInfos = std::auto_ptr<reco::JetFlavourInfoMatchingCollection>( new reco::JetFlavourInfoMatchingCollection(reco::JetRefBaseProd(subjets)) );
293 
294  // vector of constituents for reclustering jets and "ghosts"
295  std::vector<fastjet::PseudoJet> fjInputs;
296  // loop over all input jets and collect all their constituents
297  for(edm::View<reco::Jet>::const_iterator it = jets->begin(); it != jets->end(); ++it)
298  {
299  std::vector<edm::Ptr<reco::Candidate> > constituents = it->getJetConstituents();
300  std::vector<edm::Ptr<reco::Candidate> >::const_iterator m;
301  for( m = constituents.begin(); m != constituents.end(); ++m )
302  {
303  reco::CandidatePtr constit = *m;
304  if(constit->pt() == 0)
305  {
306  edm::LogWarning("NullTransverseMomentum") << "dropping input candidate with pt=0";
307  continue;
308  }
309  fjInputs.push_back(fastjet::PseudoJet(constit->px(),constit->py(),constit->pz(),constit->energy()));
310  }
311  }
312  // insert "ghost" b hadrons in the vector of constituents
313  insertGhosts(bHadrons, ghostRescaling_, true, true, false, false, fjInputs);
314  // insert "ghost" c hadrons in the vector of constituents
315  insertGhosts(cHadrons, ghostRescaling_, true, false, false, false, fjInputs);
316  // insert "ghost" partons in the vector of constituents
317  insertGhosts(partons, ghostRescaling_, false, false, true, false, fjInputs);
318  // if used, insert "ghost" leptons in the vector of constituents
319  if( useLeptons_ )
320  insertGhosts(leptons, ghostRescaling_, false, false, false, true, fjInputs);
321 
322  // define jet clustering sequence
323  fjClusterSeq_ = ClusterSequencePtr( new fastjet::ClusterSequence( fjInputs, *fjJetDefinition_ ) );
324  // recluster jet constituents and inserted "ghosts"
325  std::vector<fastjet::PseudoJet> inclusiveJets = fastjet::sorted_by_pt( fjClusterSeq_->inclusive_jets(jetPtMin_) );
326 
327  if( inclusiveJets.size() < jets->size() )
328  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.";
329 
330  // match reclustered and original jets
331  std::vector<int> reclusteredIndices;
332  matchReclusteredJets(jets,inclusiveJets,reclusteredIndices);
333 
334  // match groomed and original jets
335  std::vector<int> groomedIndices;
336  if( useSubjets_ )
337  {
338  if( groomedJets->size() > jets->size() )
339  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.";
340 
341  matchGroomedJets(jets,groomedJets,groomedIndices);
342  }
343 
344  // match subjets and original jets
345  std::vector<std::vector<int> > subjetIndices;
346  if( useSubjets_ )
347  {
348  matchSubjets(groomedIndices,groomedJets,subjets,subjetIndices);
349  }
350 
351  // determine jet flavour
352  for(size_t i=0; i<jets->size(); ++i)
353  {
354  reco::GenParticleRefVector clusteredbHadrons;
355  reco::GenParticleRefVector clusteredcHadrons;
356  reco::GenParticleRefVector clusteredPartons;
357  reco::GenParticleRefVector clusteredLeptons;
358 
359  // if matching reclustered to original jets failed
360  if( reclusteredIndices.at(i) < 0 )
361  {
362  // set an empty JetFlavourInfo for this jet
363  (*jetFlavourInfos)[jets->refAt(i)] = reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
364  }
365  else if( jets->at(i).pt() == 0 )
366  {
367  edm::LogWarning("NullTransverseMomentum") << "The original jet " << i << " has Pt=0. This is not expected so the jet will be skipped.";
368 
369  // set an empty JetFlavourInfo for this jet
370  (*jetFlavourInfos)[jets->refAt(i)] = reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, 0, 0);
371 
372  // if subjets are used
373  if( useSubjets_ && subjetIndices.at(i).size()>0 )
374  {
375  // loop over subjets
376  for(size_t sj=0; sj<subjetIndices.at(i).size(); ++sj)
377  {
378  // set an empty JetFlavourInfo for this subjet
379  (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] = reco::JetFlavourInfo(reco::GenParticleRefVector(), reco::GenParticleRefVector(), reco::GenParticleRefVector(), reco::GenParticleRefVector(), 0, 0);
380  }
381  }
382  }
383  else
384  {
385  // since the "ghosts" are extremely soft, the configuration and ordering of the reclustered and original jets should in principle stay the same
386  if( ( std::abs( inclusiveJets.at(reclusteredIndices.at(i)).pt() - jets->at(i).pt() ) / jets->at(i).pt() ) > relPtTolerance_ )
387  {
388  if( jets->at(i).pt() < 10. ) // special handling for low-Pt jets (Pt<10 GeV)
389  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"
390  << "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"
391  << "Since the mismatch is at low Pt (Pt<10 GeV), it is ignored and only a warning is issued.\n"
392  << "\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.";
393  else
394  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"
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  << "\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.";
397  }
398 
399  // get jet constituents (sorted by Pt)
400  std::vector<fastjet::PseudoJet> constituents = fastjet::sorted_by_pt( inclusiveJets.at(reclusteredIndices.at(i)).constituents() );
401 
402  // loop over jet constituents and try to find "ghosts"
403  for(std::vector<fastjet::PseudoJet>::const_iterator it = constituents.begin(); it != constituents.end(); ++it)
404  {
405  if( !it->has_user_info() ) continue; // skip if not a "ghost"
406 
407  // "ghost" hadron
408  if( it->user_info<GhostInfo>().isHadron() )
409  {
410  // "ghost" b hadron
411  if( it->user_info<GhostInfo>().isbHadron() )
412  clusteredbHadrons.push_back(it->user_info<GhostInfo>().particleRef());
413  // "ghost" c hadron
414  else
415  clusteredcHadrons.push_back(it->user_info<GhostInfo>().particleRef());
416  }
417  // "ghost" parton
418  else if( it->user_info<GhostInfo>().isParton() )
419  clusteredPartons.push_back(it->user_info<GhostInfo>().particleRef());
420  // "ghost" lepton
421  else if( it->user_info<GhostInfo>().isLepton() )
422  clusteredLeptons.push_back(it->user_info<GhostInfo>().particleRef());
423  }
424 
425  int hadronFlavour = 0; // default hadron flavour set to 0 (= undefined)
426  int partonFlavour = 0; // default parton flavour set to 0 (= undefined)
427 
428  // set hadron- and parton-based flavours
429  setFlavours(clusteredbHadrons, clusteredcHadrons, clusteredPartons, hadronFlavour, partonFlavour);
430 
431  // set the JetFlavourInfo for this jet
432  (*jetFlavourInfos)[jets->refAt(i)] = reco::JetFlavourInfo(clusteredbHadrons, clusteredcHadrons, clusteredPartons, clusteredLeptons, hadronFlavour, partonFlavour);
433  }
434 
435  // if subjets are used, determine their flavour
436  if( useSubjets_ )
437  {
438  if( subjetIndices.at(i).size()==0 ) continue; // continue if the original jet does not have subjets assigned
439 
440  // define vectors of GenParticleRefVectors for hadrons and partons assigned to different subjets
441  std::vector<reco::GenParticleRefVector> assignedbHadrons(subjetIndices.at(i).size(),reco::GenParticleRefVector());
442  std::vector<reco::GenParticleRefVector> assignedcHadrons(subjetIndices.at(i).size(),reco::GenParticleRefVector());
443  std::vector<reco::GenParticleRefVector> assignedPartons(subjetIndices.at(i).size(),reco::GenParticleRefVector());
444  std::vector<reco::GenParticleRefVector> assignedLeptons(subjetIndices.at(i).size(),reco::GenParticleRefVector());
445 
446  // loop over clustered b hadrons and assign them to different subjets based on smallest dR
447  assignToSubjets(clusteredbHadrons, subjets, subjetIndices.at(i), assignedbHadrons);
448  // loop over clustered c hadrons and assign them to different subjets based on smallest dR
449  assignToSubjets(clusteredcHadrons, subjets, subjetIndices.at(i), assignedcHadrons);
450  // loop over clustered partons and assign them to different subjets based on smallest dR
451  assignToSubjets(clusteredPartons, subjets, subjetIndices.at(i), assignedPartons);
452  // if used, loop over clustered leptons and assign them to different subjets based on smallest dR
453  if( useLeptons_ )
454  assignToSubjets(clusteredLeptons, subjets, subjetIndices.at(i), assignedLeptons);
455 
456  // loop over subjets and determine their flavour
457  for(size_t sj=0; sj<subjetIndices.at(i).size(); ++sj)
458  {
459  int subjetHadronFlavour = 0; // default hadron flavour set to 0 (= undefined)
460  int subjetPartonFlavour = 0; // default parton flavour set to 0 (= undefined)
461 
462  // set hadron- and parton-based flavours
463  setFlavours(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
464 
465  // set the JetFlavourInfo for this subjet
466  (*subjetFlavourInfos)[subjets->refAt(subjetIndices.at(i).at(sj))] = reco::JetFlavourInfo(assignedbHadrons.at(sj), assignedcHadrons.at(sj), assignedPartons.at(sj), assignedLeptons.at(sj), subjetHadronFlavour, subjetPartonFlavour);
467  }
468  }
469  }
470 
471  // put jet flavour infos in the event
472  iEvent.put( jetFlavourInfos );
473  // put subjet flavour infos in the event
474  if( useSubjets_ )
475  iEvent.put( subjetFlavourInfos, "SubJets" );
476 }
477 
478 // ------------ method that inserts "ghost" particles in the vector of jet constituents ------------
479 void
481  const double ghostRescaling,
482  const bool isHadron, const bool isbHadron, const bool isParton, const bool isLepton,
483  std::vector<fastjet::PseudoJet>& constituents)
484 {
485  // insert "ghost" particles in the vector of jet constituents
486  for(reco::GenParticleRefVector::const_iterator it = particles->begin(); it != particles->end(); ++it)
487  {
488  if((*it)->pt() == 0)
489  {
490  edm::LogInfo("NullTransverseMomentum") << "dropping input ghost candidate with pt=0";
491  continue;
492  }
493  fastjet::PseudoJet p((*it)->px(),(*it)->py(),(*it)->pz(),(*it)->energy());
494  p*=ghostRescaling; // rescale particle momentum
495  p.set_user_info(new GhostInfo(isHadron, isbHadron, isParton, isLepton, *it));
496  constituents.push_back(p);
497  }
498 }
499 
500 // ------------ method that matches reclustered and original jets based on minimum dR ------------
501 void
503  const std::vector<fastjet::PseudoJet>& reclusteredJets,
504  std::vector<int>& matchedIndices)
505 {
506  std::vector<bool> matchedLocks(reclusteredJets.size(),false);
507 
508  for(size_t j=0; j<jets->size(); ++j)
509  {
510  double matchedDR2 = 1e9;
511  int matchedIdx = -1;
512 
513  for(size_t rj=0; rj<reclusteredJets.size(); ++rj)
514  {
515  if( matchedLocks.at(rj) ) continue; // skip jets that have already been matched
516 
517  double tempDR2 = reco::deltaR2( jets->at(j).rapidity(), jets->at(j).phi(), reclusteredJets.at(rj).rapidity(), reclusteredJets.at(rj).phi_std() );
518  if( tempDR2 < matchedDR2 )
519  {
520  matchedDR2 = tempDR2;
521  matchedIdx = rj;
522  }
523  }
524 
525  if( matchedIdx>=0 )
526  {
527  if ( matchedDR2 > rParam_*rParam_ )
528  {
529  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"
530  << "This is not expected so please check that the jet algorithm and jet size match those used for the original jet collection.";
531  }
532  else
533  matchedLocks.at(matchedIdx) = true;
534  }
535  else
536  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.";
537 
538  matchedIndices.push_back(matchedIdx);
539  }
540 }
541 
542 // ------------ method that matches groomed and original jets based on minimum dR ------------
543 void
545  const edm::Handle<edm::View<reco::Jet> >& groomedJets,
546  std::vector<int>& matchedIndices)
547 {
548  std::vector<bool> jetLocks(jets->size(),false);
549  std::vector<int> jetIndices;
550 
551  for(size_t gj=0; gj<groomedJets->size(); ++gj)
552  {
553  double matchedDR2 = 1e9;
554  int matchedIdx = -1;
555 
556  if( groomedJets->at(gj).pt()>0. ) // skip pathological cases of groomed jets with Pt=0
557  {
558  for(size_t j=0; j<jets->size(); ++j)
559  {
560  if( jetLocks.at(j) ) continue; // skip jets that have already been matched
561 
562  double tempDR2 = reco::deltaR2( jets->at(j).rapidity(), jets->at(j).phi(), groomedJets->at(gj).rapidity(), groomedJets->at(gj).phi() );
563  if( tempDR2 < matchedDR2 )
564  {
565  matchedDR2 = tempDR2;
566  matchedIdx = j;
567  }
568  }
569  }
570 
571  if( matchedIdx>=0 )
572  {
573  if ( matchedDR2 > rParam_*rParam_ )
574  {
575  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"
576  << "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.";
577  matchedIdx = -1;
578  }
579  else
580  jetLocks.at(matchedIdx) = true;
581  }
582  jetIndices.push_back(matchedIdx);
583  }
584 
585  for(size_t j=0; j<jets->size(); ++j)
586  {
587  std::vector<int>::iterator matchedIndex = std::find( jetIndices.begin(), jetIndices.end(), j );
588 
589  matchedIndices.push_back( matchedIndex != jetIndices.end() ? std::distance(jetIndices.begin(),matchedIndex) : -1 );
590  }
591 }
592 
593 // ------------ method that matches subjets and original jets ------------
594 void
595 JetFlavourClustering::matchSubjets(const std::vector<int>& groomedIndices,
596  const edm::Handle<edm::View<reco::Jet> >& groomedJets,
597  const edm::Handle<edm::View<reco::Jet> >& subjets,
598  std::vector<std::vector<int> >& matchedIndices)
599 {
600  for(size_t g=0; g<groomedIndices.size(); ++g)
601  {
602  std::vector<int> subjetIndices;
603 
604  if( groomedIndices.at(g)>=0 )
605  {
606  for(size_t s=0; s<groomedJets->at(groomedIndices.at(g)).numberOfDaughters(); ++s)
607  {
608  const edm::Ptr<reco::Candidate> & subjet = groomedJets->at(groomedIndices.at(g)).daughterPtr(s);
609 
610  for(size_t sj=0; sj<subjets->size(); ++sj)
611  {
612  if( subjet == edm::Ptr<reco::Candidate>(subjets->ptrAt(sj)) )
613  {
614  subjetIndices.push_back(sj);
615  break;
616  }
617  }
618  }
619 
620  if( subjetIndices.size() == 0 )
621  edm::LogError("SubjetMatchingFailed") << "Matching subjets to original jets failed. Please check that the groomed jet and subjet collections belong to each other.";
622 
623  matchedIndices.push_back(subjetIndices);
624  }
625  else
626  matchedIndices.push_back(subjetIndices);
627  }
628 }
629 
630 // ------------ method that sets hadron- and parton-based flavours ------------
631 void
633  const reco::GenParticleRefVector& clusteredcHadrons,
634  const reco::GenParticleRefVector& clusteredPartons,
635  int& hadronFlavour,
636  int& partonFlavour)
637 {
638  reco::GenParticleRef hardestParton;
639  reco::GenParticleRef hardestLightParton;
640  reco::GenParticleRef flavourParton;
641 
642  // loop over clustered partons (already sorted by Pt)
643  for(reco::GenParticleRefVector::const_iterator it = clusteredPartons.begin(); it != clusteredPartons.end(); ++it)
644  {
645  // hardest parton
646  if( hardestParton.isNull() )
647  hardestParton = (*it);
648  // hardest light-flavour parton
649  if( hardestLightParton.isNull() )
650  {
651  if( CandMCTagUtils::isLightParton( *(*it) ) )
652  hardestLightParton = (*it);
653  }
654  // c flavour
655  if( flavourParton.isNull() && ( std::abs( (*it)->pdgId() ) == 4 ) )
656  flavourParton = (*it);
657  // b flavour gets priority
658  if( std::abs( (*it)->pdgId() ) == 5 )
659  {
660  if( flavourParton.isNull() )
661  flavourParton = (*it);
662  else if( std::abs( flavourParton->pdgId() ) != 5 )
663  flavourParton = (*it);
664  }
665  }
666 
667  // set hadron-based flavour
668  if( clusteredbHadrons.size()>0 )
669  hadronFlavour = 5;
670  else if( clusteredcHadrons.size()>0 && clusteredbHadrons.size()==0 )
671  hadronFlavour = 4;
672  // set parton-based flavour
673  if( flavourParton.isNull() )
674  {
675  if( hardestParton.isNonnull() ) partonFlavour = hardestParton->pdgId();
676  }
677  else
678  partonFlavour = flavourParton->pdgId();
679 
680  // if enabled, check for conflicts between hadron- and parton-based flavours and give priority to the hadron-based flavour
682  {
683  if( hadronFlavour==0 && (std::abs(partonFlavour)==4 || std::abs(partonFlavour)==5) )
684  partonFlavour = ( hardestLightParton.isNonnull() ? hardestLightParton->pdgId() : 0 );
685  else if( hadronFlavour!=0 && std::abs(partonFlavour)!=hadronFlavour )
686  partonFlavour = hadronFlavour;
687  }
688 }
689 
690 // ------------ method that assigns clustered particles to subjets ------------
691 void
693  const edm::Handle<edm::View<reco::Jet> >& subjets,
694  const std::vector<int>& subjetIndices,
695  std::vector<reco::GenParticleRefVector>& assignedParticles)
696 {
697  // loop over clustered particles and assign them to different subjets based on smallest dR
698  for(reco::GenParticleRefVector::const_iterator it = clusteredParticles.begin(); it != clusteredParticles.end(); ++it)
699  {
700  std::vector<double> dR2toSubjets;
701 
702  for(size_t sj=0; sj<subjetIndices.size(); ++sj)
703  dR2toSubjets.push_back( reco::deltaR2( (*it)->rapidity(), (*it)->phi(), subjets->at(subjetIndices.at(sj)).rapidity(), subjets->at(subjetIndices.at(sj)).phi() ) );
704 
705  // find the closest subjet
706  int closestSubjetIdx = std::distance( dR2toSubjets.begin(), std::min_element(dR2toSubjets.begin(), dR2toSubjets.end()) );
707 
708  assignedParticles.at(closestSubjetIdx).push_back( *it );
709  }
710 }
711 
712 // ------------ method called once each job just before starting event loop ------------
713 void
715 {
716 }
717 
718 // ------------ method called once each job just after ending the event loop ------------
719 void
721 }
722 
723 // ------------ method called when starting to processes a run ------------
724 void
726 {
727 }
728 
729 // ------------ method called when ending the processing of a run ------------
730 void
732 {
733 }
734 
735 // ------------ method called when starting to processes a luminosity block ------------
736 void
738 {
739 }
740 
741 // ------------ method called when ending the processing of a luminosity block ------------
742 void
744 {
745 }
746 
747 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
748 void
750  //The following says we do not know what parameters are allowed so do no validation
751  // Please change this to state exactly what you do use, even if it is no parameters
753  desc.setUnknown();
754  descriptions.addDefault(desc);
755 }
756 
757 //define this as a plug-in
const reco::GenParticleRef & particleRef() const
bool isLightParton(const reco::Candidate &c)
Definition: CandMCTag.cc:63
boost::shared_ptr< fastjet::JetDefinition > JetDefPtr
int i
Definition: DBlmapReader.cc:9
virtual void produce(edm::Event &, const edm::EventSetup &)
virtual void endLuminosityBlock(edm::LuminosityBlock &, edm::EventSetup const &)
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:250
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.
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:449
boost::shared_ptr< fastjet::ClusterSequence > ClusterSequencePtr
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
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)
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)
Definition: pdgIdUtils.h:19
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.
Definition: RefVector.h:249
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:7
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
Definition: Activities.doc:4
const bool isParton() const
const_iterator begin() const
Initialize an iterator over the RefVector.
Definition: RefVector.h:244
const bool isLepton() const
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
const edm::EDGetTokenT< reco::GenParticleRefVector > cHadronsToken_
int iEvent
Definition: GenABIO.cc:230
void addDefault(ParameterSetDescription const &psetDescription)
virtual void beginRun(edm::Run &, edm::EventSetup const &)
OrphanHandle< PROD > put(std::auto_ptr< PROD > product)
Put a new product.
Definition: Event.h:113
T sqrt(T t)
Definition: SSEVec.h:48
vector< PseudoJet > jets
Class storing the jet flavour information.
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int j
Definition: DBlmapReader.cc:9
double deltaR2(const T1 &t1, const T2 &t2)
Definition: deltaR.h:36
virtual void endRun(edm::Run &, edm::EventSetup const &)
JetFlavourClustering(const edm::ParameterSet &)
bool isNull() const
Checks for null.
Definition: Ref.h:247
void matchReclusteredJets(const edm::Handle< edm::View< reco::Jet > > &jets, const std::vector< fastjet::PseudoJet > &matchedJets, std::vector< int > &matchedIndices)
const std::string jetAlgorithm_
const edm::EDGetTokenT< edm::View< reco::Jet > > groomedJetsToken_
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)
Definition: CandMCTag.cc:48
boost::indirect_iterator< typename seq_t::const_iterator > const_iterator
Definition: View.h:81
const bool isbHadron() const
virtual void beginLuminosityBlock(edm::LuminosityBlock &, edm::EventSetup const &)
const bool isHadron() const
void push_back(value_type const &ref)
Add a Ref&lt;C, T&gt; to the RefVector.
Definition: RefVector.h:64
size_type size() const
Size of the RefVector.
Definition: RefVector.h:89
const edm::EDGetTokenT< reco::GenParticleRefVector > leptonsToken_
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_
const edm::EDGetTokenT< edm::View< reco::Jet > > subjetsToken_
Definition: Run.h:41
Definition: DDAxes.h:10