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 
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 = reco::tau::getTrackFromChargedHadron(*nextChargedHadron);
217 
218  // discard candidate in case its track is "used" by any ChargedHadron in the clean collection
219  bool isTrack_overlap = false;
220  if (track) {
221  double track_eta = track->eta();
222  double track_phi = track->phi();
223  for (std::list<etaPhiPair>::const_iterator trackInCleanCollection = tracksInCleanCollection.begin();
224  trackInCleanCollection != tracksInCleanCollection.end();
225  ++trackInCleanCollection) {
226  double dR = deltaR(track_eta, track_phi, trackInCleanCollection->first, trackInCleanCollection->second);
227  if (dR < 1.e-4)
228  isTrack_overlap = true;
229  }
230  }
231  if (verbosity_) {
232  edm::LogPrint("PFRecoTauChHProducer") << "isTrack_overlap = " << isTrack_overlap;
233  }
234  if (isTrack_overlap)
235  continue;
236 
237  // discard ChargedHadron candidates without track in case they are close to neutral PFCandidates "used" by ChargedHadron candidates in the clean collection
238  bool isNeutralPFCand_overlap = false;
239  if (nextChargedHadron->algoIs(reco::PFRecoTauChargedHadron::kPFNeutralHadron)) {
240  for (std::set<reco::CandidatePtr>::const_iterator neutralPFCandInCleanCollection =
241  neutralPFCandsInCleanCollection.begin();
242  neutralPFCandInCleanCollection != neutralPFCandsInCleanCollection.end();
243  ++neutralPFCandInCleanCollection) {
244  if ((*neutralPFCandInCleanCollection) == nextChargedHadron->getChargedPFCandidate())
245  isNeutralPFCand_overlap = true;
246  }
247  }
248  if (verbosity_) {
249  edm::LogPrint("PFRecoTauChHProducer") << "isNeutralPFCand_overlap = " << isNeutralPFCand_overlap;
250  }
251  if (isNeutralPFCand_overlap)
252  continue;
253 
254  // find neutral PFCandidates that are not "used" by any ChargedHadron in the clean collection
255  std::vector<reco::CandidatePtr> uniqueNeutralPFCands;
256  std::set_difference(nextChargedHadron->getNeutralPFCandidates().begin(),
257  nextChargedHadron->getNeutralPFCandidates().end(),
258  neutralPFCandsInCleanCollection.begin(),
259  neutralPFCandsInCleanCollection.end(),
260  std::back_inserter(uniqueNeutralPFCands));
261 
262  if (uniqueNeutralPFCands.size() ==
263  nextChargedHadron->getNeutralPFCandidates()
264  .size()) { // all neutral PFCandidates are unique, add ChargedHadron candidate to clean collection
265  if (track)
266  tracksInCleanCollection.push_back(std::make_pair(track->eta(), track->phi()));
267  neutralPFCandsInCleanCollection.insert(nextChargedHadron->getNeutralPFCandidates().begin(),
268  nextChargedHadron->getNeutralPFCandidates().end());
269  if (verbosity_) {
270  edm::LogPrint("PFRecoTauChHProducer") << "--> adding nextChargedHadron to output collection.";
271  }
272  cleanedChargedHadrons.push_back(*nextChargedHadron);
273  } else { // remove overlapping neutral PFCandidates, reevaluate ranking criterion and process ChargedHadron candidate again
274  nextChargedHadron->neutralPFCandidates_.clear();
275  for (auto const& neutralPFCand : uniqueNeutralPFCands) {
276  nextChargedHadron->neutralPFCandidates_.push_back(neutralPFCand);
277  }
278  // update ChargedHadron four-momentum
279  reco::tau::setChargedHadronP4(*nextChargedHadron);
280  // reinsert ChargedHadron candidate into list of uncleaned candidates,
281  // at position according to new rank
282  auto insertionPoint = std::lower_bound(uncleanedChargedHadrons.begin(),
283  uncleanedChargedHadrons.end(),
284  *nextChargedHadron,
285  [this](const auto& a, const auto& b) { return (*predicate_)(*a, b); });
286  if (verbosity_) {
287  edm::LogPrint("PFRecoTauChHProducer") << "--> removing non-unique neutral PFCandidates and reinserting "
288  "nextChargedHadron in uncleaned collection.";
289  }
290  uncleanedChargedHadrons.insert(insertionPoint, std::move(nextChargedHadron));
291  }
292  }
293 
294  if (verbosity_) {
295  for (auto const& had : cleanedChargedHadrons) {
296  print(had);
297  }
298  }
299 
300  // add ChargedHadron-to-jet association
301  pfJetChargedHadronAssociations->setValue(pfJet.key(), cleanedChargedHadrons);
302  }
303 
304  evt.put(std::move(pfJetChargedHadronAssociations));
305 }
306 
307 template <typename T>
309  edm::LogPrint("PFRecoTauChHProducer") << chargedHadron;
310  edm::LogPrint("PFRecoTauChHProducer") << "Rankers:";
311  for (auto const& ranker : rankers_) {
312  constexpr unsigned width = 25;
313  edm::LogPrint("PFRecoTauChHProducer")
314  << " " << std::setiosflags(std::ios::left) << std::setw(width) << ranker->name() << " "
315  << std::resetiosflags(std::ios::left) << std::setprecision(3) << (*ranker)(chargedHadron) << std::endl;
316  }
317 }
318 
320  // ak4PFJetsRecoTauChargedHadrons
322  {
323  edm::ParameterSetDescription desc_ranking;
324  desc_ranking.add<std::string>("selectionPassFunction", "-pt");
325  desc_ranking.add<double>("selectionFailValue", 1000.0);
326  desc_ranking.add<std::string>("selection", "algoIs(\"kChargedPFCandidate\")");
327  desc_ranking.add<std::string>("name", "ChargedPFCandidate");
328  desc_ranking.add<std::string>("plugin", "PFRecoTauChargedHadronStringQuality");
329 
330  edm::ParameterSet pset_ranking;
331  pset_ranking.addParameter<std::string>("selectionPassFunction", "-pt");
332  pset_ranking.addParameter<double>("selectionFailValue", 1000.0);
333  pset_ranking.addParameter<std::string>("selection", "algoIs(\"kChargedPFCandidate\")");
334  pset_ranking.addParameter<std::string>("name", "ChargedPFCandidate");
335  pset_ranking.addParameter<std::string>("plugin", "PFRecoTauChargedHadronStringQuality");
336  std::vector<edm::ParameterSet> vpsd_ranking;
337  vpsd_ranking.push_back(pset_ranking);
338 
339  desc.addVPSet("ranking", desc_ranking, vpsd_ranking);
340  }
341 
342  desc.add<int>("verbosity", 0);
343  desc.add<double>("maxJetAbsEta", 2.5);
344  desc.add<std::string>("outputSelection", "pt > 0.5");
345  desc.add<double>("minJetPt", 14.0);
346  desc.add<edm::InputTag>("jetSrc", edm::InputTag("ak4PFJets"));
347 
348  {
349  edm::ParameterSetDescription desc_builders;
350  desc_builders.add<double>("minMergeChargedHadronPt");
351  desc_builders.add<std::string>("name");
352  desc_builders.add<std::string>("plugin");
353  desc_builders.addOptional<double>("dRcone");
354  desc_builders.addOptional<bool>("dRconeLimitedToJetArea");
355  desc_builders.addOptional<double>("dRmergeNeutralHadron");
356  desc_builders.addOptional<double>("dRmergePhoton");
357  desc_builders.addOptional<edm::InputTag>("srcTracks");
358 
359  edm::ParameterSetDescription desc_qualityCuts;
361  desc_builders.add<edm::ParameterSetDescription>("qualityCuts", desc_qualityCuts);
362 
363  desc_builders.add<double>("minMergeGammaEt");
364  desc_builders.add<int>("verbosity", 0);
365  desc_builders.add<double>("minMergeNeutralHadronEt");
366 
367  desc_builders.addOptional<double>("dRmergePhotonWrtChargedHadron");
368  desc_builders.addOptional<double>("dRmergePhotonWrtNeutralHadron");
369  desc_builders.addOptional<int>("maxUnmatchedBlockElementsNeutralHadron");
370  desc_builders.addOptional<double>("dRmergePhotonWrtElectron");
371  desc_builders.addOptional<std::vector<int>>("chargedHadronCandidatesParticleIds");
372  desc_builders.addOptional<int>("minBlockElementMatchesPhoton");
373  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtNeutralHadron");
374  desc_builders.addOptional<int>("maxUnmatchedBlockElementsPhoton");
375  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtOther");
376  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtElectron");
377  desc_builders.addOptional<int>("minBlockElementMatchesNeutralHadron");
378  desc_builders.addOptional<double>("dRmergePhotonWrtOther");
379  desc_builders.addOptional<double>("dRmergeNeutralHadronWrtChargedHadron");
380 
381  edm::ParameterSet pset_builders;
382  pset_builders.addParameter<std::string>("name", "");
383  pset_builders.addParameter<std::string>("plugin", "");
385  pset_builders.addParameter<edm::ParameterSet>("qualityCuts", qualityCuts);
386  pset_builders.addParameter<int>("verbosity", 0);
387  std::vector<edm::ParameterSet> vpsd_builders;
388  vpsd_builders.push_back(pset_builders);
389 
390  desc.addVPSet("builders", desc_builders, vpsd_builders);
391  }
392 
393  descriptions.add("pfRecoTauChargedHadronProducer", desc);
394 }
395 
397 
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
static void fillDescriptions(edm::ParameterSetDescription &descriptions)
Declare all parameters read from python config file.
def create(alignables, pedeDump, additionalData, outputFile, config)
PFRecoTauChargedHadronProducer(const edm::ParameterSet &cfg)
std::vector< ParameterSet > VParameterSet
Definition: ParameterSet.h:35
std::vector< std::unique_ptr< Builder > > builders_
selection
main part
Definition: corrVsCorr.py:100
void produce(edm::Event &evt, const edm::EventSetup &es) override
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:526
Log< level::Error, false > LogError
edm::RefToBaseProd< reco::Jet > JetRefBaseProd
Definition: JetCollection.h:13
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
reco::tau::PFRecoTauChargedHadronBuilderPlugin Builder
reco::tau::RecoTauLexicographicalRanking< RankerList, reco::PFRecoTauChargedHadron > ChargedHadronPredicate
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:136
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< std::unique_ptr< Ranker > > RankerList
ParameterDescriptionBase * add(U const &iLabel, T const &value)
Log< level::Warning, true > LogPrint
reco::tau::PFRecoTauChargedHadronQualityPlugin Ranker
double b
Definition: hdecay.h:120
void add(std::string const &label, ParameterSetDescription const &psetDescription)
std::unique_ptr< ChargedHadronPredicate > predicate_
const reco::Track * getTrackFromChargedHadron(const reco::PFRecoTauChargedHadron &chargedHadron)
double a
Definition: hdecay.h:121
#define get
void setChargedHadronP4(reco::PFRecoTauChargedHadron &chargedHadron, double scaleFactor_neutralPFCands=1.0)
long double T
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_
def move(src, dest)
Definition: eostools.py:511