CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 
24 
30 
41 
43 
44 #include <algorithm>
45 #include <cmath>
46 #include <functional>
47 #include <list>
48 #include <memory>
49 #include <set>
50 #include <string>
51 #include <vector>
52 
54 public:
57 
60  void produce(edm::Event& evt, const edm::EventSetup& es) override;
61  template <typename T>
62  void print(const T& chargedHadron);
63 
64  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
65 
66 private:
67  typedef std::vector<std::unique_ptr<Ranker>> RankerList;
69  typedef std::list<std::unique_ptr<reco::PFRecoTauChargedHadron>> ChargedHadronList;
70 
72 
74 
75  // input jet collection
78  double minJetPt_;
79  double maxJetAbsEta_;
80 
81  // plugins for building and ranking ChargedHadron candidates
82  std::vector<std::unique_ptr<Builder>> builders_;
84 
85  std::unique_ptr<ChargedHadronPredicate> predicate_;
86 
87  // output selector
88  std::unique_ptr<StringCutObjectSelector<reco::PFRecoTauChargedHadron>> outputSelector_;
89 
90  // flag to enable/disable debug print-out
92 };
93 
95  : moduleLabel_(cfg.getParameter<std::string>("@module_label")) {
96  srcJets_ = cfg.getParameter<edm::InputTag>("jetSrc");
97  Jets_token = consumes<reco::JetView>(srcJets_);
98  minJetPt_ = cfg.getParameter<double>("minJetPt");
99  maxJetAbsEta_ = cfg.getParameter<double>("maxJetAbsEta");
100  verbosity_ = cfg.getParameter<int>("verbosity");
101 
102  // get set of ChargedHadron builder plugins
103  edm::VParameterSet psets_builders = cfg.getParameter<edm::VParameterSet>("builders");
104  for (edm::VParameterSet::const_iterator pset = psets_builders.begin(); pset != psets_builders.end(); ++pset) {
105  std::string pluginType = pset->getParameter<std::string>("plugin");
106  edm::ParameterSet pset_modified = (*pset);
107  pset_modified.addParameter<int>("verbosity", verbosity_);
108  builders_.emplace_back(
109  PFRecoTauChargedHadronBuilderPluginFactory::get()->create(pluginType, pset_modified, consumesCollector()));
110  }
111 
112  // get set of plugins for ranking ChargedHadrons in quality
113  edm::VParameterSet psets_rankers = cfg.getParameter<edm::VParameterSet>("ranking");
114  for (edm::VParameterSet::const_iterator pset = psets_rankers.begin(); pset != psets_rankers.end(); ++pset) {
115  std::string pluginType = pset->getParameter<std::string>("plugin");
116  edm::ParameterSet pset_modified = (*pset);
117  pset_modified.addParameter<int>("verbosity", verbosity_);
118  rankers_.emplace_back(PFRecoTauChargedHadronQualityPluginFactory::get()->create(pluginType, pset_modified));
119  }
120 
121  // build the sorting predicate
122  predicate_ = std::make_unique<ChargedHadronPredicate>(rankers_);
123 
124  // check if we want to apply a final output selection
125  std::string selection = cfg.getParameter<std::string>("outputSelection");
126  if (!selection.empty()) {
127  outputSelector_ = std::make_unique<StringCutObjectSelector<reco::PFRecoTauChargedHadron>>(selection);
128  }
129 
130  produces<reco::PFJetChargedHadronAssociation>();
131 }
132 
134  if (verbosity_) {
135  edm::LogPrint("PFRecoTauChHProducer") << "<PFRecoTauChargedHadronProducer::produce>:";
136  edm::LogPrint("PFRecoTauChHProducer") << " moduleLabel = " << moduleLabel_;
137  }
138 
139  // give each of our plugins a chance at doing something with the edm::Event
140  for (auto& builder : builders_) {
141  builder->setup(evt, es);
142  }
143 
144  // get a view of our jets via the base candidates
146  evt.getByToken(Jets_token, jets);
147 
148  // convert the view to a RefVector of actual PFJets
150  size_t nElements = jets->size();
151  for (size_t i = 0; i < nElements; ++i) {
152  pfJets.push_back(jets->refAt(i));
153  }
154 
155  // make our association
156  std::unique_ptr<reco::PFJetChargedHadronAssociation> pfJetChargedHadronAssociations;
157 
158  if (!pfJets.empty()) {
159  pfJetChargedHadronAssociations = std::make_unique<reco::PFJetChargedHadronAssociation>(reco::JetRefBaseProd(jets));
160  } else {
161  pfJetChargedHadronAssociations = std::make_unique<reco::PFJetChargedHadronAssociation>();
162  }
163 
164  // loop over our jets
165  for (const auto& pfJet : pfJets) {
166  if (pfJet->pt() - minJetPt_ < 1e-5)
167  continue;
168  if (std::abs(pfJet->eta()) - maxJetAbsEta_ > -1e-5)
169  continue;
170 
171  // build global list of ChargedHadron candidates for each jet
172  ChargedHadronList uncleanedChargedHadrons;
173 
174  // merge candidates reconstructed by all desired algorithm plugins
175  for (auto const& builder : builders_) {
176  try {
177  ChargedHadronVector result((*builder)(*pfJet));
178  if (verbosity_) {
179  edm::LogPrint("PFRecoTauChHProducer") << "result of builder = " << builder->name() << ":";
180  for (auto const& had : result) {
181  print(*had);
182  }
183  }
184  std::move(result.begin(), result.end(), std::back_inserter(uncleanedChargedHadrons));
185  } catch (cms::Exception& exception) {
186  edm::LogError("BuilderPluginException")
187  << "Exception caught in builder plugin " << builder->name() << ", rethrowing" << std::endl;
188  throw exception;
189  }
190  }
191 
192  // rank the candidates according to our quality plugins
193  uncleanedChargedHadrons.sort([this](const auto& a, const auto& b) { return (*predicate_)(*a, *b); });
194 
195  // define collection of cleaned ChargedHadrons;
196  std::vector<reco::PFRecoTauChargedHadron> cleanedChargedHadrons;
197 
198  // keep track of neutral PFCandidates, charged PFCandidates and tracks "used" by ChargedHadron candidates in the clean collection
199  typedef std::pair<double, double> etaPhiPair;
200  std::list<etaPhiPair> tracksInCleanCollection;
201  std::set<reco::CandidatePtr> neutralPFCandsInCleanCollection;
202 
203  while (!uncleanedChargedHadrons.empty()) {
204  // get next best ChargedHadron candidate
205  std::unique_ptr<reco::PFRecoTauChargedHadron> nextChargedHadron = std::move(uncleanedChargedHadrons.front());
206  uncleanedChargedHadrons.pop_front();
207  if (verbosity_) {
208  edm::LogPrint("PFRecoTauChHProducer") << "processing nextChargedHadron:";
209  edm::LogPrint("PFRecoTauChHProducer") << (*nextChargedHadron);
210  }
211 
212  // discard candidates which fail final output selection
213  if (!(*outputSelector_)(*nextChargedHadron))
214  continue;
215 
216  const reco::Track* track = nullptr;
217  if (nextChargedHadron->getChargedPFCandidate().isNonnull()) {
218  const reco::PFCandidate* chargedPFCand =
219  dynamic_cast<const reco::PFCandidate*>(&*nextChargedHadron->getChargedPFCandidate());
220  if (chargedPFCand) {
221  if (chargedPFCand->trackRef().isNonnull())
222  track = chargedPFCand->trackRef().get();
223  else if (chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->innerTrack().isNonnull())
224  track = chargedPFCand->muonRef()->innerTrack().get();
225  else if (chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->globalTrack().isNonnull())
226  track = chargedPFCand->muonRef()->globalTrack().get();
227  else if (chargedPFCand->muonRef().isNonnull() && chargedPFCand->muonRef()->outerTrack().isNonnull())
228  track = chargedPFCand->muonRef()->outerTrack().get();
229  else if (chargedPFCand->gsfTrackRef().isNonnull())
230  track = chargedPFCand->gsfTrackRef().get();
231  } else {
232  track = nextChargedHadron->getChargedPFCandidate()->bestTrack();
233  }
234  }
235  if (track == nullptr) {
236  if (nextChargedHadron->getTrack().isNonnull()) {
237  track = nextChargedHadron->getTrack().get();
238  } else if (nextChargedHadron->getLostTrackCandidate().isNonnull()) {
239  track = nextChargedHadron->getLostTrackCandidate()->bestTrack();
240  }
241  }
242 
243  // discard candidate in case its track is "used" by any ChargedHadron in the clean collection
244  bool isTrack_overlap = false;
245  if (track) {
246  double track_eta = track->eta();
247  double track_phi = track->phi();
248  for (std::list<etaPhiPair>::const_iterator trackInCleanCollection = tracksInCleanCollection.begin();
249  trackInCleanCollection != tracksInCleanCollection.end();
250  ++trackInCleanCollection) {
251  double dR = deltaR(track_eta, track_phi, trackInCleanCollection->first, trackInCleanCollection->second);
252  if (dR < 1.e-4)
253  isTrack_overlap = true;
254  }
255  }
256  if (verbosity_) {
257  edm::LogPrint("PFRecoTauChHProducer") << "isTrack_overlap = " << isTrack_overlap;
258  }
259  if (isTrack_overlap)
260  continue;
261 
262  // discard ChargedHadron candidates without track in case they are close to neutral PFCandidates "used" by ChargedHadron candidates in the clean collection
263  bool isNeutralPFCand_overlap = false;
264  if (nextChargedHadron->algoIs(reco::PFRecoTauChargedHadron::kPFNeutralHadron)) {
265  for (std::set<reco::CandidatePtr>::const_iterator neutralPFCandInCleanCollection =
266  neutralPFCandsInCleanCollection.begin();
267  neutralPFCandInCleanCollection != neutralPFCandsInCleanCollection.end();
268  ++neutralPFCandInCleanCollection) {
269  if ((*neutralPFCandInCleanCollection) == nextChargedHadron->getChargedPFCandidate())
270  isNeutralPFCand_overlap = true;
271  }
272  }
273  if (verbosity_) {
274  edm::LogPrint("PFRecoTauChHProducer") << "isNeutralPFCand_overlap = " << isNeutralPFCand_overlap;
275  }
276  if (isNeutralPFCand_overlap)
277  continue;
278 
279  // find neutral PFCandidates that are not "used" by any ChargedHadron in the clean collection
280  std::vector<reco::CandidatePtr> uniqueNeutralPFCands;
281  std::set_difference(nextChargedHadron->getNeutralPFCandidates().begin(),
282  nextChargedHadron->getNeutralPFCandidates().end(),
283  neutralPFCandsInCleanCollection.begin(),
284  neutralPFCandsInCleanCollection.end(),
285  std::back_inserter(uniqueNeutralPFCands));
286 
287  if (uniqueNeutralPFCands.size() ==
288  nextChargedHadron->getNeutralPFCandidates()
289  .size()) { // all neutral PFCandidates are unique, add ChargedHadron candidate to clean collection
290  if (track)
291  tracksInCleanCollection.push_back(std::make_pair(track->eta(), track->phi()));
292  neutralPFCandsInCleanCollection.insert(nextChargedHadron->getNeutralPFCandidates().begin(),
293  nextChargedHadron->getNeutralPFCandidates().end());
294  if (verbosity_) {
295  edm::LogPrint("PFRecoTauChHProducer") << "--> adding nextChargedHadron to output collection.";
296  }
297  cleanedChargedHadrons.push_back(*nextChargedHadron);
298  } else { // remove overlapping neutral PFCandidates, reevaluate ranking criterion and process ChargedHadron candidate again
299  nextChargedHadron->neutralPFCandidates_.clear();
300  for (auto const& neutralPFCand : uniqueNeutralPFCands) {
301  nextChargedHadron->neutralPFCandidates_.push_back(neutralPFCand);
302  }
303  // update ChargedHadron four-momentum
304  reco::tau::setChargedHadronP4(*nextChargedHadron);
305  // reinsert ChargedHadron candidate into list of uncleaned candidates,
306  // at position according to new rank
307  auto insertionPoint = std::lower_bound(uncleanedChargedHadrons.begin(),
308  uncleanedChargedHadrons.end(),
309  *nextChargedHadron,
310  [this](const auto& a, const auto& b) { return (*predicate_)(*a, b); });
311  if (verbosity_) {
312  edm::LogPrint("PFRecoTauChHProducer") << "--> removing non-unique neutral PFCandidates and reinserting "
313  "nextChargedHadron in uncleaned collection.";
314  }
315  uncleanedChargedHadrons.insert(insertionPoint, std::move(nextChargedHadron));
316  }
317  }
318 
319  if (verbosity_) {
320  for (auto const& had : cleanedChargedHadrons) {
321  print(had);
322  }
323  }
324 
325  // add ChargedHadron-to-jet association
326  pfJetChargedHadronAssociations->setValue(pfJet.key(), cleanedChargedHadrons);
327  }
328 
329  evt.put(std::move(pfJetChargedHadronAssociations));
330 }
331 
332 template <typename T>
333 void PFRecoTauChargedHadronProducer::print(const T& chargedHadron) {
334  edm::LogPrint("PFRecoTauChHProducer") << chargedHadron;
335  edm::LogPrint("PFRecoTauChHProducer") << "Rankers:";
336  for (auto const& ranker : rankers_) {
337  constexpr unsigned width = 25;
338  edm::LogPrint("PFRecoTauChHProducer")
339  << " " << std::setiosflags(std::ios::left) << std::setw(width) << ranker->name() << " "
340  << std::resetiosflags(std::ios::left) << std::setprecision(3) << (*ranker)(chargedHadron) << std::endl;
341  }
342 }
343 
345  // ak4PFJetsRecoTauChargedHadrons
347  {
348  edm::ParameterSetDescription desc_ranking;
349  desc_ranking.add<std::string>("selectionPassFunction", "-pt");
350  desc_ranking.add<double>("selectionFailValue", 1000.0);
351  desc_ranking.add<std::string>("selection", "algoIs(\"kChargedPFCandidate\")");
352  desc_ranking.add<std::string>("name", "ChargedPFCandidate");
353  desc_ranking.add<std::string>("plugin", "PFRecoTauChargedHadronStringQuality");
354 
355  edm::ParameterSet pset_ranking;
356  pset_ranking.addParameter<std::string>("selectionPassFunction", "-pt");
357  pset_ranking.addParameter<double>("selectionFailValue", 1000.0);
358  pset_ranking.addParameter<std::string>("selection", "algoIs(\"kChargedPFCandidate\")");
359  pset_ranking.addParameter<std::string>("name", "ChargedPFCandidate");
360  pset_ranking.addParameter<std::string>("plugin", "PFRecoTauChargedHadronStringQuality");
361  std::vector<edm::ParameterSet> vpsd_ranking;
362  vpsd_ranking.push_back(pset_ranking);
363 
364  desc.addVPSet("ranking", desc_ranking, vpsd_ranking);
365  }
366 
367  desc.add<int>("verbosity", 0);
368  desc.add<double>("maxJetAbsEta", 2.5);
369  desc.add<std::string>("outputSelection", "pt > 0.5");
370  desc.add<double>("minJetPt", 14.0);
371  desc.add<edm::InputTag>("jetSrc", edm::InputTag("ak4PFJets"));
372 
373  {
374  edm::ParameterSetDescription desc_builders;
375  desc_builders.add<double>("minMergeChargedHadronPt");
376  desc_builders.add<std::string>("name");
377  desc_builders.add<std::string>("plugin");
378  desc_builders.addOptional<double>("dRcone");
379  desc_builders.addOptional<bool>("dRconeLimitedToJetArea");
380  desc_builders.addOptional<double>("dRmergeNeutralHadron");
381  desc_builders.addOptional<double>("dRmergePhoton");
382  desc_builders.addOptional<edm::InputTag>("srcTracks");
383 
384  edm::ParameterSetDescription desc_qualityCuts;
386  desc_builders.add<edm::ParameterSetDescription>("qualityCuts", desc_qualityCuts);
387 
388  desc_builders.add<double>("minMergeGammaEt");
389  desc_builders.add<int>("verbosity", 0);
390  desc_builders.add<double>("minMergeNeutralHadronEt");
391 
392  desc_builders.addOptional<double>("dRmergePhotonWrtChargedHadron");
393  desc_builders.addOptional<double>("dRmergePhotonWrtNeutralHadron");
394  desc_builders.addOptional<int>("maxUnmatchedBlockElementsNeutralHadron");
395  desc_builders.addOptional<double>("dRmergePhotonWrtElectron");
396  desc_builders.addOptional<std::vector<int>>("chargedHadronCandidatesParticleIds");
397  desc_builders.addOptional<int>("minBlockElementMatchesPhoton");
398  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtNeutralHadron");
399  desc_builders.addOptional<int>("maxUnmatchedBlockElementsPhoton");
400  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtOther");
401  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtElectron");
402  desc_builders.addOptional<int>("minBlockElementMatchesNeutralHadron");
403  desc_builders.addOptional<double>("dRmergePhotonWrtOther");
404  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtChargedHadron");
405 
406  edm::ParameterSet pset_builders;
407  pset_builders.addParameter<std::string>("name", "");
408  pset_builders.addParameter<std::string>("plugin", "");
410  pset_builders.addParameter<edm::ParameterSet>("qualityCuts", qualityCuts);
411  pset_builders.addParameter<int>("verbosity", 0);
412  std::vector<edm::ParameterSet> vpsd_builders;
413  vpsd_builders.push_back(pset_builders);
414 
415  desc.addVPSet("builders", desc_builders, vpsd_builders);
416  }
417 
418  descriptions.add("pfRecoTauChargedHadronProducer", desc);
419 }
420 
422 
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:133
ParameterDescriptionBase * addOptional(U const &iLabel, T const &value)
edm::EDGetTokenT< reco::JetView > Jets_token
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
tuple cfg
Definition: looper.py:296
ParameterDescriptionBase * addVPSet(U const &iLabel, ParameterSetDescription const &validator, std::vector< ParameterSet > const &defaults)
static void fillDescriptions(edm::ParameterSetDescription &descriptions)
Declare all parameters read from python config file.
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:539
PFRecoTauChargedHadronProducer(const edm::ParameterSet &cfg)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< ParameterSet > VParameterSet
Definition: ParameterSet.h:34
std::vector< std::unique_ptr< Builder > > builders_
selection
main part
Definition: corrVsCorr.py:100
double phi() const
azimuthal angle of momentum vector
Definition: TrackBase.h:649
void produce(edm::Event &evt, const edm::EventSetup &es) override
Log< level::Error, false > LogError
tuple result
Definition: mps_fire.py:311
reco::TrackRef trackRef() const
Definition: PFCandidate.cc:430
edm::RefToBaseProd< reco::Jet > JetRefBaseProd
Definition: JetCollection.h:13
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
double eta() const
pseudorapidity of momentum vector
Definition: TrackBase.h:652
reco::tau::PFRecoTauChargedHadronBuilderPlugin Builder
reco::tau::RecoTauLexicographicalRanking< RankerList, reco::PFRecoTauChargedHadron > ChargedHadronPredicate
vector< PseudoJet > jets
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:135
def move
Definition: eostools.py:511
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
T const * get() const
Returns C++ pointer to the item.
Definition: Ref.h:232
std::vector< std::unique_ptr< Ranker > > RankerList
ParameterDescriptionBase * add(U const &iLabel, T const &value)
Log< level::Warning, true > LogPrint
reco::MuonRef muonRef() const
Definition: PFCandidate.cc:443
reco::tau::PFRecoTauChargedHadronQualityPlugin Ranker
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
double b
Definition: hdecay.h:118
void add(std::string const &label, ParameterSetDescription const &psetDescription)
std::unique_ptr< ChargedHadronPredicate > predicate_
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:41
__host__ __device__ constexpr RandomIt lower_bound(RandomIt first, RandomIt last, const T &value, Compare comp={})
double a
Definition: hdecay.h:119
reco::GsfTrackRef gsfTrackRef() const
Definition: PFCandidate.cc:462
void push_back(const RefToBase< T > &)
#define get
void setChargedHadronP4(reco::PFRecoTauChargedHadron &chargedHadron, double scaleFactor_neutralPFCands=1.0)
moduleLabel_(iConfig.getParameter< string >("@module_label"))
long double T
tuple pfJets
Definition: pfJets_cff.py:8
std::list< std::unique_ptr< reco::PFRecoTauChargedHadron > > ChargedHadronList
std::vector< std::string > set_difference(std::vector< std::string > const &v1, std::vector< std::string > const &v2)
std::unique_ptr< StringCutObjectSelector< reco::PFRecoTauChargedHadron > > outputSelector_