CMS 3D CMS Logo

PFRecoTauChargedHadronProducer.cc
Go to the documentation of this file.
1 /*
2  * PFRecoTauChargedHadronProducer
3  *
4  * Author: Christian Veelken, LLR
5  *
6  * Associates reconstructed ChargedHadrons to PFJets. The ChargedHadrons are built using one
7  * or more RecoTauBuilder plugins. Any overlaps (ChargedHadrons sharing tracks)
8  * are removed, with the best ChargedHadron candidates taken. The 'best' are defined
9  * via the input list of PFRecoTauChargedHadronQualityPlugins, which form a
10  * lexicograpical ranking.
11  *
12  */
13 
18 
21 
26 
37 
39 
40 #include <boost/ptr_container/ptr_vector.hpp>
41 #include <boost/ptr_container/ptr_list.hpp>
42 #include <boost/foreach.hpp>
43 
44 #include <string>
45 #include <vector>
46 #include <list>
47 #include <set>
48 #include <algorithm>
49 #include <functional>
50 #include <cmath>
51 
53 {
54 public:
57 
60  void produce(edm::Event& evt, const edm::EventSetup& es) override;
61  template <typename T>
62  void print(const T& chargedHadrons);
63 
64  private:
65  typedef boost::ptr_vector<Builder> builderList;
66  typedef boost::ptr_vector<Ranker> rankerList;
67  typedef boost::ptr_vector<reco::PFRecoTauChargedHadron> ChargedHadronVector;
68  typedef boost::ptr_list<reco::PFRecoTauChargedHadron> ChargedHadronList;
69 
71 
73 
74  // input jet collection
77  double minJetPt_;
78  double maxJetAbsEta_;
79 
80  // plugins for building and ranking ChargedHadron candidates
81  builderList builders_;
82  rankerList rankers_;
83 
84  std::auto_ptr<ChargedHadronPredicate> predicate_;
85 
86  // output selector
87  std::auto_ptr<StringCutObjectSelector<reco::PFRecoTauChargedHadron> > outputSelector_;
88 
89  // flag to enable/disable debug print-out
91 };
92 
94  : moduleLabel_(cfg.getParameter<std::string>("@module_label"))
95 {
96  srcJets_ = cfg.getParameter<edm::InputTag>("jetSrc");
97  Jets_token = consumes<reco::CandidateView>(srcJets_);
98  minJetPt_ = ( cfg.exists("minJetPt") ) ? cfg.getParameter<double>("minJetPt") : -1.0;
99  maxJetAbsEta_ = ( cfg.exists("maxJetAbsEta") ) ? cfg.getParameter<double>("maxJetAbsEta") : 99.0;
100  verbosity_ = ( cfg.exists("verbosity") ) ?
101  cfg.getParameter<int>("verbosity") : 0;
102 
103  // get set of ChargedHadron builder plugins
104  edm::VParameterSet psets_builders = cfg.getParameter<edm::VParameterSet>("builders");
105  for ( edm::VParameterSet::const_iterator pset = psets_builders.begin();
106  pset != psets_builders.end(); ++pset ) {
107  std::string pluginType = pset->getParameter<std::string>("plugin");
108  edm::ParameterSet pset_modified = (*pset);
109  pset_modified.addParameter<int>("verbosity", verbosity_);
110  builders_.push_back(PFRecoTauChargedHadronBuilderPluginFactory::get()->create(pluginType, pset_modified, consumesCollector()));
111  }
112 
113  // get set of plugins for ranking ChargedHadrons in quality
114  edm::VParameterSet psets_rankers = cfg.getParameter<edm::VParameterSet>("ranking");
115  for ( edm::VParameterSet::const_iterator pset = psets_rankers.begin();
116  pset != psets_rankers.end(); ++pset ) {
117  std::string pluginType = pset->getParameter<std::string>("plugin");
118  edm::ParameterSet pset_modified = (*pset);
119  pset_modified.addParameter<int>("verbosity", verbosity_);
120  rankers_.push_back(PFRecoTauChargedHadronQualityPluginFactory::get()->create(pluginType, pset_modified));
121  }
122 
123  // build the sorting predicate
124  predicate_ = std::auto_ptr<ChargedHadronPredicate>(new ChargedHadronPredicate(rankers_));
125 
126  // check if we want to apply a final output selection
127  if ( cfg.exists("outputSelection") ) {
128  std::string selection = cfg.getParameter<std::string>("outputSelection");
129  if ( selection != "" ) {
131  }
132  }
133 
134  produces<reco::PFJetChargedHadronAssociation>();
135 }
136 
138 {
139  if ( verbosity_ ) {
140  edm::LogPrint("PFRecoTauChHProducer")<< "<PFRecoTauChargedHadronProducer::produce>:" ;
141  edm::LogPrint("PFRecoTauChHProducer")<< " moduleLabel = " << moduleLabel_ ;
142  }
143 
144  // give each of our plugins a chance at doing something with the edm::Event
145  BOOST_FOREACH( Builder& builder, builders_ ) {
146  builder.setup(evt, es);
147  }
148 
149  // get a view of our jets via the base candidates
151  evt.getByToken(Jets_token, jets);
152 
153  // convert the view to a RefVector of actual PFJets
154  reco::PFJetRefVector pfJets = reco::tau::castView<reco::PFJetRefVector>(jets);
155 
156  // make our association
157  std::unique_ptr<reco::PFJetChargedHadronAssociation> pfJetChargedHadronAssociations;
158 
159 
160  if ( !pfJets.empty() ) {
161  edm::Handle<reco::PFJetCollection> pfJetCollectionHandle;
162  evt.get(pfJets.id(), pfJetCollectionHandle);
163  pfJetChargedHadronAssociations = std::make_unique<reco::PFJetChargedHadronAssociation>(reco::PFJetRefProd(pfJetCollectionHandle));
164  } else {
165  pfJetChargedHadronAssociations = std::make_unique<reco::PFJetChargedHadronAssociation>();
166  }
167 
168  // loop over our jets
169  BOOST_FOREACH( const reco::PFJetRef& pfJet, pfJets ) {
170 
171  if(pfJet->pt() - minJetPt_ < 1e-5) continue;
172  if(std::abs(pfJet->eta()) - maxJetAbsEta_ > -1e-5) continue;
173 
174  // build global list of ChargedHadron candidates for each jet
175  ChargedHadronList uncleanedChargedHadrons;
176 
177  // merge candidates reconstructed by all desired algorithm plugins
178  BOOST_FOREACH( const Builder& builder, builders_ ) {
179  try {
180  ChargedHadronVector result(builder(*pfJet));
181  if ( verbosity_ ) {
182  edm::LogPrint("PFRecoTauChHProducer")<< "result of builder = " << builder.name() << ":" ;
183  print(result);
184  }
185  uncleanedChargedHadrons.transfer(uncleanedChargedHadrons.end(), result);
186  } catch ( cms::Exception& exception ) {
187  edm::LogError("BuilderPluginException")
188  << "Exception caught in builder plugin " << builder.name()
189  << ", rethrowing" << std::endl;
190  throw exception;
191  }
192  }
193 
194  // rank the candidates according to our quality plugins
195  uncleanedChargedHadrons.sort(*predicate_);
196 
197  // define collection of cleaned ChargedHadrons;
198  std::vector<reco::PFRecoTauChargedHadron> cleanedChargedHadrons;
199 
200  // keep track of neutral PFCandidates, charged PFCandidates and tracks "used" by ChargedHadron candidates in the clean collection
201  typedef std::pair<double, double> etaPhiPair;
202  std::list<etaPhiPair> tracksInCleanCollection;
203  std::set<reco::PFCandidatePtr> neutralPFCandsInCleanCollection;
204 
205  while ( !uncleanedChargedHadrons.empty() ) {
206 
207  // get next best ChargedHadron candidate
208  std::auto_ptr<reco::PFRecoTauChargedHadron> nextChargedHadron(uncleanedChargedHadrons.pop_front().release());
209  if ( verbosity_ ) {
210  edm::LogPrint("PFRecoTauChHProducer")<< "processing nextChargedHadron:" ;
211  edm::LogPrint("PFRecoTauChHProducer")<< (*nextChargedHadron);
212  }
213 
214  // discard candidates which fail final output selection
215  if ( !(*outputSelector_)(*nextChargedHadron) ) continue;
216 
217  const reco::Track* track = nullptr;
218  if ( nextChargedHadron->getChargedPFCandidate().isNonnull() ) {
219  const reco::PFCandidatePtr& chargedPFCand = nextChargedHadron->getChargedPFCandidate();
220  if ( chargedPFCand->trackRef().isNonnull() ) track = chargedPFCand->trackRef().get();
221  else if ( chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->innerTrack().isNonnull() ) track = chargedPFCand->muonRef()->innerTrack().get();
222  else if ( chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->globalTrack().isNonnull() ) track = chargedPFCand->muonRef()->globalTrack().get();
223  else if ( chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->outerTrack().isNonnull() ) track = chargedPFCand->muonRef()->outerTrack().get();
224  else if ( chargedPFCand->gsfTrackRef().isNonnull() ) track = chargedPFCand->gsfTrackRef().get();
225  }
226  if ( nextChargedHadron->getTrack().isNonnull() && !track ) {
227  track = nextChargedHadron->getTrack().get();
228  }
229 
230  // discard candidate in case its track is "used" by any ChargedHadron in the clean collection
231  bool isTrack_overlap = false;
232  if ( track ) {
233  double track_eta = track->eta();
234  double track_phi = track->phi();
235  for ( std::list<etaPhiPair>::const_iterator trackInCleanCollection = tracksInCleanCollection.begin();
236  trackInCleanCollection != tracksInCleanCollection.end(); ++trackInCleanCollection ) {
237  double dR = deltaR(track_eta, track_phi, trackInCleanCollection->first, trackInCleanCollection->second);
238  if ( dR < 1.e-4 ) isTrack_overlap = true;
239  }
240  }
241  if ( verbosity_ ) {
242  edm::LogPrint("PFRecoTauChHProducer")<< "isTrack_overlap = " << isTrack_overlap ;
243  }
244  if ( isTrack_overlap ) continue;
245 
246  // discard ChargedHadron candidates without track in case they are close to neutral PFCandidates "used" by ChargedHadron candidates in the clean collection
247  bool isNeutralPFCand_overlap = false;
248  if ( nextChargedHadron->algoIs(reco::PFRecoTauChargedHadron::kPFNeutralHadron) ) {
249  for ( std::set<reco::PFCandidatePtr>::const_iterator neutralPFCandInCleanCollection = neutralPFCandsInCleanCollection.begin();
250  neutralPFCandInCleanCollection != neutralPFCandsInCleanCollection.end(); ++neutralPFCandInCleanCollection ) {
251  if ( (*neutralPFCandInCleanCollection) == nextChargedHadron->getChargedPFCandidate() ) isNeutralPFCand_overlap = true;
252  }
253  }
254  if ( verbosity_ ) {
255  edm::LogPrint("PFRecoTauChHProducer")<< "isNeutralPFCand_overlap = " << isNeutralPFCand_overlap ;
256  }
257  if ( isNeutralPFCand_overlap ) continue;
258 
259  // find neutral PFCandidates that are not "used" by any ChargedHadron in the clean collection
260  std::vector<reco::PFCandidatePtr> uniqueNeutralPFCands;
261  std::set_difference(nextChargedHadron->getNeutralPFCandidates().begin(),
262  nextChargedHadron->getNeutralPFCandidates().end(),
263  neutralPFCandsInCleanCollection.begin(),
264  neutralPFCandsInCleanCollection.end(),
265  std::back_inserter(uniqueNeutralPFCands));
266 
267  if ( uniqueNeutralPFCands.size() == nextChargedHadron->getNeutralPFCandidates().size() ) { // all neutral PFCandidates are unique, add ChargedHadron candidate to clean collection
268  if ( track ) tracksInCleanCollection.push_back(std::make_pair(track->eta(), track->phi()));
269  neutralPFCandsInCleanCollection.insert(nextChargedHadron->getNeutralPFCandidates().begin(), nextChargedHadron->getNeutralPFCandidates().end());
270  if ( verbosity_ ) {
271  edm::LogPrint("PFRecoTauChHProducer")<< "--> adding nextChargedHadron to output collection." ;
272  }
273  cleanedChargedHadrons.push_back(*nextChargedHadron);
274  } else { // remove overlapping neutral PFCandidates, reevaluate ranking criterion and process ChargedHadron candidate again
275  nextChargedHadron->neutralPFCandidates_.clear();
276  BOOST_FOREACH( const reco::PFCandidatePtr& neutralPFCand, uniqueNeutralPFCands ) {
277  nextChargedHadron->neutralPFCandidates_.push_back(neutralPFCand);
278  }
279  // update ChargedHadron four-momentum
280  reco::tau::setChargedHadronP4(*nextChargedHadron);
281  // reinsert ChargedHadron candidate into list of uncleaned candidates,
282  // at position according to new rank
283  ChargedHadronList::iterator insertionPoint = std::lower_bound(uncleanedChargedHadrons.begin(), uncleanedChargedHadrons.end(), *nextChargedHadron, *predicate_);
284  if ( verbosity_ ) {
285  edm::LogPrint("PFRecoTauChHProducer")<< "--> removing non-unique neutral PFCandidates and reinserting nextChargedHadron in uncleaned collection." ;
286  }
287  uncleanedChargedHadrons.insert(insertionPoint, nextChargedHadron);
288  }
289  }
290 
291  if ( verbosity_ ) {
292  print(cleanedChargedHadrons);
293  }
294 
295  // add ChargedHadron-to-jet association
296  pfJetChargedHadronAssociations->setValue(pfJet.key(), cleanedChargedHadrons);
297  }
298 
299  evt.put(std::move(pfJetChargedHadronAssociations));
300 }
301 
302 template <typename T>
303 void PFRecoTauChargedHadronProducer::print(const T& chargedHadrons)
304 {
305  for ( typename T::const_iterator chargedHadron = chargedHadrons.begin();
306  chargedHadron != chargedHadrons.end(); ++chargedHadron ) {
307  edm::LogPrint("PFRecoTauChHProducer") << (*chargedHadron);
308  edm::LogPrint("PFRecoTauChHProducer") << "Rankers:" ;
309  for ( rankerList::const_iterator ranker = rankers_.begin();
310  ranker != rankers_.end(); ++ranker) {
311  const unsigned width = 25;
312  edm::LogPrint("PFRecoTauChHProducer") << " " << std::setiosflags(std::ios::left) << std::setw(width) << ranker->name()
313  << " " << std::resetiosflags(std::ios::left) << std::setprecision(3) << (*ranker)(*chargedHadron) << std::endl;
314  }
315  }
316 }
317 
319 
T getParameter(std::string const &) const
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:127
def create(alignables, pedeDump, additionalData, outputFile, config)
reco::tau::RecoTauLexicographicalRanking< rankerList, reco::PFRecoTauChargedHadron > ChargedHadronPredicate
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:508
PFRecoTauChargedHadronProducer(const edm::ParameterSet &cfg)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
std::vector< ParameterSet > VParameterSet
Definition: ParameterSet.h:33
T const * get() const
Returns C++ pointer to the item.
Definition: Ptr.h:159
selection
main part
Definition: corrVsCorr.py:98
bool exists(std::string const &parameterName) const
checks if a parameter exists
double phi() const
azimuthal angle of momentum vector
Definition: TrackBase.h:645
void produce(edm::Event &evt, const edm::EventSetup &es) override
key_type key() const
Accessor for product key.
Definition: Ref.h:265
bool empty() const
Is the RefVector empty.
Definition: RefVector.h:104
edm::EDGetTokenT< reco::CandidateView > Jets_token
void setup(edm::Event &, const edm::EventSetup &)
double eta() const
pseudorapidity of momentum vector
Definition: TrackBase.h:651
reco::tau::PFRecoTauChargedHadronBuilderPlugin Builder
ProductID id() const
Accessor for product ID.
Definition: RefVector.h:122
boost::ptr_vector< reco::PFRecoTauChargedHadron > ChargedHadronVector
ConsumesCollector consumesCollector()
Use a ConsumesCollector to gather consumes information from helper functions.
std::auto_ptr< ChargedHadronPredicate > predicate_
vector< PseudoJet > jets
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:144
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool get(ProductID const &oid, Handle< PROD > &result) const
Definition: Event.h:330
edm::RefProd< PFJetCollection > PFJetRefProd
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:168
double deltaR(double eta1, double eta2, double phi1, double phi2)
Definition: TreeUtility.cc:17
reco::tau::PFRecoTauChargedHadronQualityPlugin Ranker
std::auto_ptr< StringCutObjectSelector< reco::PFRecoTauChargedHadron > > outputSelector_
boost::ptr_list< reco::PFRecoTauChargedHadron > ChargedHadronList
const std::string & name() const
void setChargedHadronP4(reco::PFRecoTauChargedHadron &chargedHadron, double scaleFactor_neutralPFCands=1.0)
long double T
def move(src, dest)
Definition: eostools.py:510
T get(const Candidate &c)
Definition: component.h:55