CMS 3D CMS Logo

RecoTauBuilderConePlugin.cc
Go to the documentation of this file.
1 /*
2  * RecoTauBuilderConePlugin
3  *
4  * Build a PFTau using cones defined in DeltaR.
5  *
6  * Original Authors: Ludovic Houchu, Simone Gennai
7  * Modifications: Evan K. Friis
8  *
9  */
10 
11 #include <vector>
12 #include <algorithm>
13 
18 
21 
27 
29 
30 namespace reco {
31  namespace tau {
32 
33  typedef std::vector<RecoTauPiZero> PiZeroList;
34 
36  public:
39  // Build a tau from a jet
41  const std::vector<reco::PFRecoTauChargedHadron>& chargedHadrons,
42  const std::vector<RecoTauPiZero>& piZeros,
43  const std::vector<CandidatePtr>& regionalExtras) const override;
44 
45  private:
46  std::unique_ptr<RecoTauQualityCuts> qcuts_;
47 
49 
51 
52  /* String function to extract values from PFJets */
54 
55  // Cone defintions
64 
68 
69  void setTauQuantities(reco::PFTau& aTau,
73  double minRelPhotonSumPt_outsideSignalCone = 1.e+9) const;
74  };
75 
76  // ctor - initialize all of our variables
79  qcuts_(new RecoTauQualityCuts(pset.getParameterSet("qualityCuts").getParameterSet("signalQualityCuts"))),
80  usePFLeptonsAsChargedHadrons_(pset.getParameter<bool>("usePFLeptons")),
81  leadObjecPtThreshold_(pset.getParameter<double>("leadObjectPt")),
82  matchingCone_(pset.getParameter<std::string>("matchingCone")),
83  signalConeChargedHadrons_(pset.getParameter<std::string>("signalConeChargedHadrons")),
84  isoConeChargedHadrons_(pset.getParameter<std::string>("isoConeChargedHadrons")),
85  signalConePiZeros_(pset.getParameter<std::string>("signalConePiZeros")),
86  signalConeSizeToStore_( //MB: stored inside PFTau and used to compte photon-pt-out-of-signal-cone and DM hypothsis
87  pset.getParameter<std::string>("signalConePiZeros")),
88  isoConePiZeros_(pset.getParameter<std::string>("isoConePiZeros")),
89  signalConeNeutralHadrons_(pset.getParameter<std::string>("signalConeNeutralHadrons")),
90  isoConeNeutralHadrons_(pset.getParameter<std::string>("isoConeNeutralHadrons")),
91  maxSignalConeChargedHadrons_(pset.getParameter<int>("maxSignalConeChargedHadrons")),
92  minAbsPhotonSumPt_insideSignalCone_(pset.getParameter<double>("minAbsPhotonSumPt_insideSignalCone")),
93  minRelPhotonSumPt_insideSignalCone_(pset.getParameter<double>("minRelPhotonSumPt_insideSignalCone"))
94 
95  {}
96 
97  namespace xclean {
98  // define template specialization for cross-cleaning
99  template <>
101  const cone::CandPtrDRFilterIter& signalTracksBegin, const cone::CandPtrDRFilterIter& signalTracksEnd) {
102  // Get the list of objects we need to clean
103  for (cone::CandPtrDRFilterIter signalTrack = signalTracksBegin; signalTrack != signalTracksEnd; ++signalTrack) {
104  toRemove_.insert(reco::CandidatePtr(*signalTrack));
105  }
106  }
107 
108  template <>
109  inline void CrossCleanPtrs<PiZeroList::const_iterator>::initialize(const PiZeroList::const_iterator& piZerosBegin,
110  const PiZeroList::const_iterator& piZerosEnd) {
111  for (auto const& ptr : flattenPiZeros(piZerosBegin, piZerosEnd)) {
112  toRemove_.insert(CandidatePtr(ptr));
113  }
114  }
115  } // namespace xclean
116 
122  //MB: Set tau quantities which are computed by RecoTauConstructor::get()
123  // method with PFRecoTauChargedHadrons not used here
124 
125  // Set charge
126  int charge = 0;
127  int leadCharge = aTau.leadChargedHadrCand().isNonnull() ? aTau.leadChargedHadrCand()->charge() : 0;
128  const std::vector<reco::CandidatePtr>& pfChs = aTau.signalChargedHadrCands();
129  for (const reco::CandidatePtr& pfCh : pfChs) {
130  charge += pfCh->charge();
131  }
132  charge = charge == 0 ? leadCharge : charge;
133  aTau.setCharge(charge);
134 
135  // Set PDG id
136  aTau.setPdgId(aTau.charge() < 0 ? 15 : -15);
137 
138  // Set Decay Mode
140  unsigned int nPiZeros = 0;
141  const std::vector<RecoTauPiZero>& piZeros = aTau.signalPiZeroCandidates();
142  for (const RecoTauPiZero& piZero : piZeros) {
143  double photonSumPt_insideSignalCone = 0.;
144  double photonSumPt_outsideSignalCone = 0.;
145  int numPhotons = piZero.numberOfDaughters();
146  for (int idxPhoton = 0; idxPhoton < numPhotons; ++idxPhoton) {
147  const reco::Candidate* photon = piZero.daughter(idxPhoton);
148  double dR = deltaR(photon->p4(), aTau.p4());
149  if (dR < aTau.signalConeSize()) {
150  photonSumPt_insideSignalCone += photon->pt();
151  } else {
152  photonSumPt_outsideSignalCone += photon->pt();
153  }
154  }
155  if (photonSumPt_insideSignalCone > minAbsPhotonSumPt_insideSignalCone ||
156  photonSumPt_insideSignalCone > (minRelPhotonSumPt_insideSignalCone * aTau.pt()) ||
157  photonSumPt_outsideSignalCone > minAbsPhotonSumPt_outsideSignalCone ||
158  photonSumPt_outsideSignalCone > (minRelPhotonSumPt_outsideSignalCone * aTau.pt()))
159  ++nPiZeros;
160  }
161  // Find the maximum number of PiZeros our parameterization can hold
162  const unsigned int maxPiZeros = PFTau::kOneProngNPiZero;
163  // Determine our track index
164  unsigned int nCharged = pfChs.size();
165  if (nCharged > 0) {
166  unsigned int trackIndex = (nCharged - 1) * (maxPiZeros + 1);
167  // Check if we handle the given number of tracks
168  if (trackIndex >= PFTau::kRareDecayMode)
170  else
171  dm = static_cast<PFTau::hadronicDecayMode>(trackIndex + std::min(nPiZeros, maxPiZeros));
172  } else {
173  dm = PFTau::kNull;
174  }
175  aTau.setDecayMode(dm);
176  return;
177  }
178 
180  const reco::JetBaseRef& jet,
181  const std::vector<reco::PFRecoTauChargedHadron>& chargedHadrons,
182  const std::vector<RecoTauPiZero>& piZeros,
183  const std::vector<CandidatePtr>& regionalExtras) const {
184  //std::cout << "<RecoTauBuilderConePlugin::operator()>:" << std::endl;
185  //std::cout << " jet: Pt = " << jet->pt() << ", eta = " << jet->eta() << ", phi = " << jet->phi() << std::endl;
186 
187  // Get access to our cone tools
188  using namespace cone;
189  // Define output. We only produce one tau per jet for the cone algo.
191 
192  // Our tau builder - the true indicates to automatically copy gamma candidates
193  // from the pizeros.
195  getPFCands(),
196  true,
200  // Setup our quality cuts to use the current vertex (supplied by base class)
201  qcuts_->setPV(primaryVertex(jet));
202 
203  typedef std::vector<CandidatePtr> CandPtrs;
204 
205  // Get the PF Charged hadrons + quality cuts
206  CandPtrs pfchs;
208  pfchs = qcuts_->filterCandRefs(pfCandidatesByPdgId(*jet, 211));
209  } else {
210  // Check if we want to include electrons in muons in "charged hadron"
211  // collection. This is the preferred behavior, as the PF lepton selections
212  // are very loose.
213  pfchs = qcuts_->filterCandRefs(pfChargedCands(*jet));
214  }
215 
216  // CV: sort collection of PF Charged hadrons by descending Pt
217  std::sort(pfchs.begin(), pfchs.end(), SortPFCandsDescendingPt());
218 
219  // Get the PF gammas
220  CandPtrs pfGammas = qcuts_->filterCandRefs(pfCandidatesByPdgId(*jet, 22));
221  // Neutral hadrons
222  CandPtrs pfnhs = qcuts_->filterCandRefs(pfCandidatesByPdgId(*jet, 130));
223 
224  // All the extra junk
225  CandPtrs regionalJunk = qcuts_->filterCandRefs(regionalExtras);
226 
227  /***********************************************
228  ****** Lead Candidate Finding **********
229  ***********************************************/
230 
231  // Define our matching cone and filters
232  double matchingCone = matchingCone_(*jet);
233  CandPtrDRFilter matchingConeFilter(jet->p4(), 0, matchingCone);
234 
235  // Find the maximum PFCharged hadron in the matching cone. The call to
236  // PFCandidates always a sorted list, so we can just take the first if it
237  // if it exists.
238  CandidatePtr leadPFCH;
239  CandPtrs::iterator leadPFCH_iter = std::find_if(pfchs.begin(), pfchs.end(), matchingConeFilter);
240 
241  if (leadPFCH_iter != pfchs.end()) {
242  leadPFCH = *leadPFCH_iter;
243  // Set leading candidate
244  tau.setleadChargedHadrCand(leadPFCH);
245  } else {
246  // If there is no leading charged candidate at all, return nothing - the
247  // producer class that owns the plugin will build a null tau if desired.
248  return output;
249  }
250 
251  // Find the leading neutral candidate
252  CandidatePtr leadPFGamma;
253  CandPtrs::iterator leadPFGamma_iter = std::find_if(pfGammas.begin(), pfGammas.end(), matchingConeFilter);
254 
255  if (leadPFGamma_iter != pfGammas.end()) {
256  leadPFGamma = *leadPFGamma_iter;
257  // Set leading neutral candidate
258  tau.setleadNeutralCand(leadPFGamma);
259  }
260 
261  CandidatePtr leadPFCand;
262  // Always use the leadPFCH if it is above our threshold
263  if (leadPFCH.isNonnull() && leadPFCH->pt() > leadObjecPtThreshold_) {
264  leadPFCand = leadPFCH;
265  } else if (leadPFGamma.isNonnull() && leadPFGamma->pt() > leadObjecPtThreshold_) {
266  // Otherwise use the lead Gamma if it is above threshold
267  leadPFCand = leadPFGamma;
268  } else {
269  // If both are too low PT, just take the charged one
270  leadPFCand = leadPFCH;
271  }
272 
273  tau.setleadCand(leadPFCand);
274 
275  // Our cone axis is defined about the lead charged hadron
276  reco::Candidate::LorentzVector coneAxis = leadPFCH->p4();
277 
278  /***********************************************
279  ****** Cone Construction **********
280  ***********************************************/
281 
282  // Define the signal and isolation cone sizes for this jet and build filters
283  // to select elements in the given DeltaR regions
284 
285  CandPtrDRFilter signalConePFCHFilter(coneAxis, -0.1, signalConeChargedHadrons_(*jet));
286  CandPtrDRFilter signalConePFNHFilter(coneAxis, -0.1, signalConeNeutralHadrons_(*jet));
287  PiZeroDRFilter signalConePiZeroFilter(coneAxis, -0.1, signalConePiZeros_(*jet));
288 
289  CandPtrDRFilter isoConePFCHFilter(coneAxis, signalConeChargedHadrons_(*jet), isoConeChargedHadrons_(*jet));
290  CandPtrDRFilter isoConePFGammaFilter(coneAxis, signalConePiZeros_(*jet), isoConePiZeros_(*jet));
291  CandPtrDRFilter isoConePFNHFilter(coneAxis, signalConeNeutralHadrons_(*jet), isoConeNeutralHadrons_(*jet));
292  PiZeroDRFilter isoConePiZeroFilter(coneAxis, signalConePiZeros_(*jet), isoConePiZeros_(*jet));
293 
294  // Additionally make predicates to select the different PF object types
295  // of the regional junk objects to add to the iso cone.
297 
298  xclean::FilterCandByAbsPdgId pfchCandSelector(211);
299  xclean::FilterCandByAbsPdgId pfgammaCandSelector(22);
300  xclean::FilterCandByAbsPdgId pfnhCandSelector(130);
301 
302  // Predicate to select the regional junk in the iso cone by PF id
303  RegionalJunkConeAndIdFilter pfChargedJunk(pfchCandSelector, // select charged stuff from junk
304  isoConePFCHFilter // only take those in iso cone
305  );
306 
307  RegionalJunkConeAndIdFilter pfGammaJunk(pfgammaCandSelector, // select gammas from junk
308  isoConePFGammaFilter // only take those in iso cone
309  );
310 
311  RegionalJunkConeAndIdFilter pfNeutralJunk(pfnhCandSelector, // select neutral stuff from junk
312  isoConePFNHFilter // select stuff in iso cone
313  );
314 
315  // Build filter iterators select the signal charged stuff.
316  CandPtrDRFilterIter signalPFCHCands_begin(signalConePFCHFilter, pfchs.begin(), pfchs.end());
317  CandPtrDRFilterIter signalPFCHCands_end(signalConePFCHFilter, pfchs.end(), pfchs.end());
318  CandPtrs signalPFCHs;
319  int numSignalPFCHs = 0;
320  CandPtrs isolationPFCHs;
321  for (CandPtrDRFilterIter iter = signalPFCHCands_begin; iter != signalPFCHCands_end; ++iter) {
322  if (numSignalPFCHs < maxSignalConeChargedHadrons_ || maxSignalConeChargedHadrons_ == -1) {
323  //std::cout << "adding signalPFCH #" << numSignalPFCHs << ": Pt = " << (*iter)->pt() << ", eta = " << (*iter)->eta() << ", phi = " << (*iter)->phi() << std::endl;
324  signalPFCHs.push_back(*iter);
325  ++numSignalPFCHs;
326  } else {
327  //std::cout << "maxSignalConeChargedHadrons reached"
328  isolationPFCHs.push_back(*iter);
329  }
330  }
331  CandPtrs::const_iterator signalPFCHs_begin = signalPFCHs.begin();
332  CandPtrs::const_iterator signalPFCHs_end = signalPFCHs.end();
333 
334  // Cross clean pi zero content using signal cone charged hadron constituents.
335  xclean::CrossCleanPiZeros<CandPtrDRFilterIter> piZeroXCleaner(signalPFCHCands_begin, signalPFCHCands_end);
336  std::vector<reco::RecoTauPiZero> cleanPiZeros = piZeroXCleaner(piZeros);
337 
338  // For the rest of the constituents, we need to filter any constituents that
339  // are already contained in the pizeros (i.e. electrons)
340  xclean::CrossCleanPtrs<PiZeroList::const_iterator> pfCandXCleaner(cleanPiZeros.begin(), cleanPiZeros.end());
341 
342  auto isolationPFCHCands_begin(boost::make_filter_iterator(
343  xclean::makePredicateAND(isoConePFCHFilter, pfCandXCleaner), pfchs.begin(), pfchs.end()));
344  auto isolationPFCHCands_end(boost::make_filter_iterator(
345  xclean::makePredicateAND(isoConePFCHFilter, pfCandXCleaner), pfchs.end(), pfchs.end()));
346  for (auto iter = isolationPFCHCands_begin; iter != isolationPFCHCands_end; ++iter) {
347  isolationPFCHs.push_back(*iter);
348  }
349  CandPtrs::const_iterator isolationPFCHs_begin = isolationPFCHs.begin();
350  CandPtrs::const_iterator isolationPFCHs_end = isolationPFCHs.end();
351 
352  // Build signal charged hadrons
353  tau.addPFCands(
354  RecoTauConstructor::kSignal, RecoTauConstructor::kChargedHadron, signalPFCHs_begin, signalPFCHs_end);
355 
356  tau.addPFCands(RecoTauConstructor::kSignal,
358  boost::make_filter_iterator(
359  xclean::makePredicateAND(signalConePFNHFilter, pfCandXCleaner), pfnhs.begin(), pfnhs.end()),
360  boost::make_filter_iterator(
361  xclean::makePredicateAND(signalConePFNHFilter, pfCandXCleaner), pfnhs.end(), pfnhs.end()));
362 
363  // Build signal PiZeros
364  tau.addPiZeros(RecoTauConstructor::kSignal,
365  PiZeroDRFilterIter(signalConePiZeroFilter, cleanPiZeros.begin(), cleanPiZeros.end()),
366  PiZeroDRFilterIter(signalConePiZeroFilter, cleanPiZeros.end(), cleanPiZeros.end()));
367 
368  // Build isolation charged hadrons
369  tau.addPFCands(
370  RecoTauConstructor::kIsolation, RecoTauConstructor::kChargedHadron, isolationPFCHs_begin, isolationPFCHs_end);
371 
372  // Add all the stuff in the isolation cone that wasn't in the jet constituents
375  boost::make_filter_iterator(pfChargedJunk, regionalJunk.begin(), regionalJunk.end()),
376  boost::make_filter_iterator(pfChargedJunk, regionalJunk.end(), regionalJunk.end()));
377 
378  // Build isolation neutral hadrons
381  boost::make_filter_iterator(
382  xclean::makePredicateAND(isoConePFNHFilter, pfCandXCleaner), pfnhs.begin(), pfnhs.end()),
383  boost::make_filter_iterator(
384  xclean::makePredicateAND(isoConePFNHFilter, pfCandXCleaner), pfnhs.end(), pfnhs.end()));
385 
386  // Add regional stuff not in jet
389  boost::make_filter_iterator(pfNeutralJunk, regionalJunk.begin(), regionalJunk.end()),
390  boost::make_filter_iterator(pfNeutralJunk, regionalJunk.end(), regionalJunk.end()));
391 
392  // Build isolation PiZeros
394  PiZeroDRFilterIter(isoConePiZeroFilter, cleanPiZeros.begin(), cleanPiZeros.end()),
395  PiZeroDRFilterIter(isoConePiZeroFilter, cleanPiZeros.end(), cleanPiZeros.end()));
396 
397  // Add regional stuff not in jet
400  boost::make_filter_iterator(pfGammaJunk, regionalJunk.begin(), regionalJunk.end()),
401  boost::make_filter_iterator(pfGammaJunk, regionalJunk.end(), regionalJunk.end()));
402 
403  // Put our built tau in the output - 'false' indicates don't build the
404  // leading candidates, we already did that explicitly above.
405 
406  std::unique_ptr<reco::PFTau> tauPtr = tau.get(false);
407 
408  // Set event vertex position for tau
409  reco::VertexRef primaryVertexRef = primaryVertex(*tauPtr);
410  if (primaryVertexRef.isNonnull())
411  tauPtr->setVertex(primaryVertexRef->position());
412 
413  // Set missing tau quantities
415 
416  output.push_back(std::move(tauPtr));
417  return output;
418  }
419  } // namespace tau
420 } // namespace reco
421 
std::vector< CandidatePtr > pfCandidatesByPdgId(const Jet &jet, int pdgId, bool sort=true)
void setTauQuantities(reco::PFTau &aTau, double minAbsPhotonSumPt_insideSignalCone=2.5, double minRelPhotonSumPt_insideSignalCone=0., double minAbsPhotonSumPt_outsideSignalCone=1.e+9, double minRelPhotonSumPt_outsideSignalCone=1.e+9) const
std::unique_ptr< RecoTauQualityCuts > qcuts_
double signalConeSize() const
Size of signal cone.
Definition: PFTau.h:174
std::vector< std::unique_ptr< reco::PFTau > > output_type
double pt() const final
transverse momentum
return_type operator()(const reco::JetBaseRef &jet, const std::vector< reco::PFRecoTauChargedHadron > &chargedHadrons, const std::vector< RecoTauPiZero > &piZeros, const std::vector< CandidatePtr > &regionalExtras) const override
const std::vector< RecoTauPiZero > & signalPiZeroCandidates() const
Retrieve the association of signal region gamma candidates into candidate PiZeros.
Definition: PFTau.cc:240
const CandidatePtr & leadChargedHadrCand() const
Definition: PFTau.cc:63
const edm::Handle< edm::View< reco::Candidate > > & getPFCands() const
Hack to be able to convert Ptrs to Refs.
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:238
RecoTauBuilderConePlugin(const edm::ParameterSet &pset, edm::ConsumesCollector &&iC)
std::vector< CandidatePtr > pfChargedCands(const Jet &jet, bool sort=true)
Extract all non-neutral candidates from a PFJet.
const LorentzVector & p4() const final
four-momentum Lorentz vector
StringObjectFunction< reco::PFTau > signalConeSizeToStore_
std::vector< CandidatePtr > flattenPiZeros(const std::vector< RecoTauPiZero >::const_iterator &, const std::vector< RecoTauPiZero >::const_iterator &)
Flatten a list of pi zeros into a list of there constituent PFCandidates.
void setCharge(Charge q) final
set electric charge
reco::VertexRef primaryVertex(const reco::JetBaseRef &jet) const
Get primary vertex associated to this jet.
std::vector< reco::CandidatePtr > CandPtrs
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:146
void setDecayMode(const hadronicDecayMode &)
Definition: PFTau.cc:327
boost::filter_iterator< CandPtrDRFilter, std::vector< CandidatePtr >::const_iterator > CandPtrDRFilterIter
Definition: ConeTools.h:47
boost::filter_iterator< PiZeroDRFilter, std::vector< RecoTauPiZero >::const_iterator > PiZeroDRFilterIter
Definition: ConeTools.h:54
void initialize(const PtrIter &chargedHadronsBegin, const PtrIter &chargedHadronsEnd)
constexpr auto deltaR(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:30
edm::Ptr< Candidate > CandidatePtr
persistent reference to an object in a collection of Candidate objects
Definition: CandidateFwd.h:25
DeltaRPtrFilter< CandidatePtr > CandPtrDRFilter
Definition: ConeTools.h:46
DeltaRFilter< RecoTauPiZero > PiZeroDRFilter
Definition: ConeTools.h:53
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Candidate.h:36
ParameterSet const & getParameterSet(ParameterSetID const &id)
const std::vector< reco::CandidatePtr > & signalChargedHadrCands() const
Charged hadrons in signal region.
Definition: PFTau.cc:76
fixed size matrix
hadronicDecayMode
Definition: PFTau.h:38
#define DEFINE_EDM_PLUGIN(factory, type, name)
StringObjectFunction< reco::Jet > JetFunc
void setPdgId(int pdgId) final
void initialize(const PtrIter &particlesBegin, const PtrIter &particlesEnd)
std::vector< RecoTauPiZero > PiZeroList
def move(src, dest)
Definition: eostools.py:511
Transform a pizero to remove given candidates.
int charge() const final
electric charge
std::vector< CandidatePtr > pfGammas(const Jet &jet, bool sort=true)
Extract all pfGammas from a PFJet.
PredicateAND< P1, P2 > makePredicateAND(const P1 &p1, const P2 &p2)