CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
PFRecoTauDecayModeDeterminator.cc
Go to the documentation of this file.
1 /* class PFRecoTauDecayModeDeterminator
2  *
3  * Takes PFCandidates from PFTau and reconstructs tau decay mode.
4  * Notably, merges photons (PFGammas) into pi zeros.
5  * PFChargedHadrons are assumed to be charged pions.
6  * Output candidate collections are owned (as shallow clones) by this object.
7  *
8  * author: Evan K. Friis, UC Davis (evan.klose.friis@cern.ch)
9  */
10 
18 
27 
33 
34 #include "CLHEP/Random/RandGauss.h"
35 
36 #include <memory>
37 #include <algorithm>
38 
39 using namespace reco;
40 using namespace edm;
41 using namespace std;
43 
45  public:
46 
47  typedef std::list<CompositeCandidate> compCandList;
48  typedef std::list<CompositeCandidate>::reverse_iterator compCandRevIter;
49 
50  void mergePiZeroes(compCandList&, compCandRevIter);
51  void mergePiZeroesByBestMatch(compCandList&);
52 
53  explicit PFRecoTauDecayModeDeterminator(const edm::ParameterSet& iConfig);
55  virtual void produce(edm::Event&,const edm::EventSetup&);
56 
57  protected:
58  const double chargedPionMass;
59  const double neutralPionMass;
60 
62  double matchQuality;
63  size_t firstIndex;
64  size_t secondIndex;
65  };
66 
67  static bool gammaMatchSorter (const gammaMatchContainer& first, const gammaMatchContainer& second);
68 
69  private:
73  uint32_t maxPhotonsToMerge_; //number of photons allowed in a merged pi0
74  double maxPiZeroMass_;
83  double minPtFractionForSecondProng_; //2 prongs whose second prong falls under
88 };
89 
90 PFRecoTauDecayModeDeterminator::PFRecoTauDecayModeDeterminator(const edm::ParameterSet& iConfig):chargedPionMass(0.13957),neutralPionMass(0.13497){
91  PFTauProducer_ = iConfig.getParameter<edm::InputTag>("PFTauProducer");
92  maxPhotonsToMerge_ = iConfig.getParameter<uint32_t>("maxPhotonsToMerge");
93  maxPiZeroMass_ = iConfig.getParameter<double>("maxPiZeroMass");
94  mergeLowPtPhotonsFirst_ = iConfig.getParameter<bool>("mergeLowPtPhotonsFirst");
95  mergeByBestMatch_ = iConfig.getParameter<bool>("mergeByBestMatch");
96  setChargedPionMass_ = iConfig.getParameter<bool>("setChargedPionMass");
97  setPi0Mass_ = iConfig.getParameter<bool>("setPi0Mass");
98  setMergedPi0Mass_ = iConfig.getParameter<bool>("setMergedPi0Mass");
99  refitTracks_ = iConfig.getParameter<bool>("refitTracks");
100  filterTwoProngs_ = iConfig.getParameter<bool>("filterTwoProngs");
101  filterPhotons_ = iConfig.getParameter<bool>("filterPhotons");
102  minPtFractionForSecondProng_ = iConfig.getParameter<double>("minPtFractionForSecondProng");
103  minPtFractionSinglePhotons_ = iConfig.getParameter<double>("minPtFractionSinglePhotons");
104  minPtFractionPiZeroes_ = iConfig.getParameter<double>("minPtFractionPiZeroes");
105  //setup vertex fitter
107  produces<PFTauDecayModeAssociation>();
108 }
109 
111 {
112 // delete vertexFitter_; //now a very small memory leak, fix me later
113 }
114 
115 
116 /*
117  * ******************************************************************
118  ** Merges a list of photons in to Pi0 candidates **
119  ******************************************************************
120  */
122 {
123  //uses std::list instead of vector, so that iterators can be deleted in situ
124  //we go backwards for historical reasons ;)
125  if(seed == input.rend())
126  return;
127  compCandRevIter bestMatchSoFar;
128  LorentzVector combinationCandidate;
129  float closestInvariantMassDifference = maxPiZeroMass_ + 1;
130  bool foundACompatibleMatch = false;
131  //find the best match to make a pi0
132  compCandRevIter potentialMatch = seed;
133  ++potentialMatch;
134  for(; potentialMatch != input.rend(); ++potentialMatch)
135  {
136  // see how close this combination comes to the pion mass
137  LorentzVector seedFourVector = seed->p4();
138  LorentzVector toAddFourVect = potentialMatch->p4();
139  combinationCandidate = seedFourVector + toAddFourVect;
140  float combinationCandidateMass = combinationCandidate.M();
141  float differenceToTruePiZeroMass = std::abs(combinationCandidateMass - neutralPionMass);
142  if(combinationCandidateMass < maxPiZeroMass_ && differenceToTruePiZeroMass < closestInvariantMassDifference)
143  {
144  closestInvariantMassDifference = differenceToTruePiZeroMass;
145  bestMatchSoFar = potentialMatch;
146  foundACompatibleMatch = true;
147  }
148  }
149  //if we found a combination that might make a pi0, combine it into the seed gamma, erase it, then see if we can add anymore
150  if(foundACompatibleMatch && seed->numberOfDaughters() < maxPhotonsToMerge_)
151  {
152  //combine match into Seed and update four vector
153  if(bestMatchSoFar->numberOfDaughters() > 0)
154  {
155  const Candidate* photonToAdd = (*bestMatchSoFar).daughter(0);
156  seed->addDaughter(*photonToAdd);
157  }
158  addP4.set(*seed);
159  //remove match as it is now contained in the seed
160  input.erase( (++bestMatchSoFar).base() ); //convert to normal iterator, after correct for offset
161  mergePiZeroes(input, seed);
162  } else
163  {
164  // otherwise move to next highest object and recurse
165  addP4.set(*seed);
166  ++seed;
167  mergePiZeroes(input, seed);
168  }
169 }
170 
171 bool
174 {
175  return (first.matchQuality < second.matchQuality);
176 }
177 
179 {
180  if(!input.size()) //nothing to merge... (NOTE: this line is necessary, as for size_t x, x in [0, +inf), x < -1 = true)
181  return;
182 
183  std::vector<compCandList::iterator> gammas; // iterators to all the gammas. needed as we are using a list for compatability
184  // with the original merging algorithm, and this implementation requires random access
185  std::vector<gammaMatchContainer> matches;
186 
187  // populate the list of gammas
188  for(compCandList::iterator iGamma = input.begin(); iGamma != input.end(); ++iGamma)
189  gammas.push_back(iGamma);
190 
191 
192  for(size_t gammaA = 0; gammaA < gammas.size()-1; ++gammaA)
193  {
194  for(size_t gammaB = gammaA+1; gammaB < gammas.size(); ++gammaB)
195  {
196  //construct invariant mass of this pair
197  LorentzVector piZeroAB = gammas[gammaA]->p4() + gammas[gammaB]->p4();
198  //different to true pizero mass
199  double piZeroABMass = piZeroAB.M();
200  double differenceToTruePiZeroMass = std::abs(piZeroABMass - neutralPionMass);
201 
202  if(piZeroABMass < maxPiZeroMass_)
203  {
204  gammaMatchContainer aMatch;
205  aMatch.matchQuality = differenceToTruePiZeroMass;
206  aMatch.firstIndex = gammaA;
207  aMatch.secondIndex = gammaB;
208  matches.push_back(aMatch);
209  }
210  }
211  }
212 
213  sort(matches.begin(), matches.end(), gammaMatchSorter);
214  //the pairs whose mass is closest to the true pi0 mass are now at the beginning
215  //of this vector
216 
217  for(std::vector<gammaMatchContainer>::iterator iMatch = matches.begin();
218  iMatch != matches.end();
219  ++iMatch)
220  {
221  size_t gammaA = iMatch->firstIndex;
222  size_t gammaB = iMatch->secondIndex;
223  //check to see that both gammas in this match have not been used (ie their iterators set to input.end())
224  if( gammas[gammaA] != input.end() && gammas[gammaB] != input.end() )
225  {
226  //merge the second gamma into the first; loop occurs in case of multiple gamma merging option
227  for(size_t bDaughter = 0; bDaughter < gammas[gammaB]->numberOfDaughters(); ++bDaughter)
228  gammas[gammaA]->addDaughter( *(gammas[gammaB]->daughter(bDaughter)) );
229  //update the four vector information
230  addP4.set(*gammas[gammaA]);
231  //delete gammaB from the list of photons/pi zeroes, as it has been merged into gammaA
232  input.erase(gammas[gammaB]);
233  //mark both as "merged"
234  gammas[gammaA] = input.end();
235  gammas[gammaB] = input.end();
236  } // else this match contains a photon that has already been merged
237  }
238 
239 }
240 
242 
243  edm::ESHandle<TransientTrackBuilder> myTransientTrackBuilder;
245 
246  if (refitTracks_)
247  {
248  iSetup.get<TransientTrackRecord>().get("TransientTrackBuilder",myTransientTrackBuilder);
249  iSetup.get<IdealMagneticFieldRecord>().get(myMF);
250  }
251 
252  edm::Handle<PFTauCollection> thePFTauCollection;
253  iEvent.getByLabel(PFTauProducer_,thePFTauCollection);
254 
255  auto_ptr<PFTauDecayModeAssociation> result(new PFTauDecayModeAssociation(PFTauRefProd(thePFTauCollection)));
256 
257  size_t numberOfPFTaus = thePFTauCollection->size();
258  for(size_t iPFTau = 0; iPFTau < numberOfPFTaus; ++iPFTau)
259  {
260  //get the reference to the PFTau
261  PFTauRef pfTauRef(thePFTauCollection, iPFTau);
262  PFTau myPFTau = *pfTauRef;
263 
264  //get the charged & neutral collections corresponding to this PFTau
265  const PFCandidateRefVector& theChargedHadronCandidates = myPFTau.signalPFChargedHadrCands();
266  const PFCandidateRefVector& theGammaCandidates = myPFTau.signalPFGammaCands();
267 
268  LorentzVector totalFourVector; //contains non-filtered stuff only.
269 
270  //shallow clone everything
271  std::vector<ShallowCloneCandidate> chargedCandidates;
272  std::list<CompositeCandidate> gammaCandidates;
273  VertexCompositeCandidate chargedCandsToAdd;
274  CompositeCandidate filteredStuff; //empty for now.
275 
276  bool needToProcessTracks = true;
277  if (filterTwoProngs_ && theChargedHadronCandidates.size() == 2)
278  {
279  size_t indexOfHighestPt = (theChargedHadronCandidates[0]->pt() > theChargedHadronCandidates[1]->pt()) ? 0 : 1;
280  size_t indexOfLowerPt = ( indexOfHighestPt ) ? 0 : 1;
281  //maybe include a like signed requirement?? (future)
282  double highPt = theChargedHadronCandidates[indexOfHighestPt]->pt();
283  double lowPt = theChargedHadronCandidates[indexOfLowerPt]->pt();
284  if (lowPt/highPt < minPtFractionForSecondProng_) //if it is super low, filter it!
285  {
286  needToProcessTracks = false; //we are doing it here instead
287  chargedCandsToAdd.addDaughter(ShallowCloneCandidate(CandidateBaseRef(theChargedHadronCandidates[indexOfHighestPt])));
288  Candidate* justAdded = chargedCandsToAdd.daughter(chargedCandsToAdd.numberOfDaughters()-1);
289  totalFourVector += justAdded->p4();
291  justAdded->setMass(chargedPionMass);
292  //add the two prong to the list of filtered stuff (to be added to the isolation collection later)
293  filteredStuff.addDaughter(ShallowCloneCandidate(CandidateBaseRef(theChargedHadronCandidates[indexOfLowerPt])));
294  }
295  }
296 
297  if(needToProcessTracks) //not a two prong, filter is turned off, or 2nd prong passes cuts
298  {
299  for( PFCandidateRefVector::const_iterator iCharged = theChargedHadronCandidates.begin();
300  iCharged != theChargedHadronCandidates.end();
301  ++iCharged)
302  {
303  // copy as shallow clone, and asssume mass of pi+
304  chargedCandsToAdd.addDaughter(ShallowCloneCandidate(CandidateBaseRef(*iCharged)));
305  Candidate* justAdded = chargedCandsToAdd.daughter(chargedCandsToAdd.numberOfDaughters()-1);
306  totalFourVector += justAdded->p4();
308  justAdded->setMass(chargedPionMass);
309  }
310  }
311 
312  for( PFCandidateRefVector::const_iterator iGamma = theGammaCandidates.begin();
313  iGamma != theGammaCandidates.end();
314  ++iGamma)
315  {
316  CompositeCandidate potentialPiZero;
317  potentialPiZero.addDaughter(ShallowCloneCandidate(CandidateBaseRef(*iGamma)));
318  addP4.set(potentialPiZero);
319  totalFourVector += potentialPiZero.p4();
320  gammaCandidates.push_back(potentialPiZero);
321  }
322 
323  //sort the photons by pt before passing to merger
325  gammaCandidates.sort(candDescendingSorter);
326  else
327  gammaCandidates.sort(candAscendingSorter);
328 
329  if (mergeByBestMatch_)
330  mergePiZeroesByBestMatch(gammaCandidates);
331  else
332  mergePiZeroes(gammaCandidates, gammaCandidates.rbegin());
333 
334  if (filterPhotons_)
335  {
336  //sort by pt, from high to low.
337  gammaCandidates.sort(candAscendingSorter);
338 
339  compCandRevIter wimp = gammaCandidates.rbegin();
340 
341  bool doneFiltering = false;
342  while(!doneFiltering && wimp != gammaCandidates.rend())
343  {
344  double ptFraction = wimp->pt()/totalFourVector.pt();
345  size_t numberOfPhotons = wimp->numberOfDaughters();
346 
347  //check if it is a single photon or has been merged
348  if ( (numberOfPhotons == 1 && ptFraction < minPtFractionSinglePhotons_) ||
349  (numberOfPhotons > 1 && ptFraction < minPtFractionPiZeroes_ ) )
350  {
351  //remove
352  totalFourVector -= wimp->p4();
353  for(size_t iDaughter = 0; iDaughter < numberOfPhotons; ++iDaughter)
354  {
355  filteredStuff.addDaughter(ShallowCloneCandidate(CandidateBaseRef( wimp->daughter(iDaughter)->masterClone() )));
356  }
357 
358  //move to the next photon to filter
359  ++wimp;
360  } else
361  {
362  //if this pizero passes the filter, we are done looking
363  doneFiltering = true;
364  }
365  }
366  //delete the filtered objects
367  gammaCandidates.erase(wimp.base(), gammaCandidates.end());
368  }
369 
370 
371  CompositeCandidate mergedPiZerosToAdd;
372  for( std::list<CompositeCandidate>::iterator iGamma = gammaCandidates.begin();
373  iGamma != gammaCandidates.end();
374  ++iGamma)
375  {
376  if (setPi0Mass_) // set mass as pi 0
377  {
378  if (iGamma->numberOfDaughters() == 1) // for merged gamma pairs, check if user wants to keep ECAL mass
379  iGamma->setMass(neutralPionMass);
380  else if (setMergedPi0Mass_)
381  iGamma->setMass(neutralPionMass);
382  }
383  mergedPiZerosToAdd.addDaughter(*iGamma);
384  }
385 
386  // apply vertex fitting.
387  if (refitTracks_ && chargedCandsToAdd.numberOfDaughters() > 1)
388  {
389  vertexFitter_->set(myMF.product());
390  vertexFitter_->set(chargedCandsToAdd); //refits tracks, adds vertexing info
391  }
392 
393  // correctly set the four vectors of the composite candidates
394  addP4.set(chargedCandsToAdd);
395  addP4.set(mergedPiZerosToAdd);
396  addP4.set(filteredStuff);
397 
398  /*
399  LorentzVector refitFourVector = chargedCandsToAdd.p4() + mergedPiZerosToAdd.p4();
400 
401  edm::LogInfo("PFTauDecayModeDeterminator") << "Found nCharged: " << chargedCandsToAdd.numberOfDaughters()
402  << " and nNeutral: " << mergedPiZerosToAdd.numberOfDaughters()
403  << " Former mass: " << totalFourVector.mass()
404  << " New mass: " << refitFourVector.mass();
405  */
406 
407  PFTauDecayMode myDecayModeTau(chargedCandsToAdd, mergedPiZerosToAdd, filteredStuff);
408  myDecayModeTau.setPFTauRef(pfTauRef);
409  result->setValue(iPFTau, myDecayModeTau);
410  }
411  iEvent.put(result);
412 }
tuple base
Main Program
Definition: newFWLiteAna.py:92
T getParameter(std::string const &) const
virtual const Candidate * daughter(size_type i) const =0
return daughter at a given position, i = 0, ... numberOfDaughters() - 1 (read only mode) ...
void setPFTauRef(const PFTauRef &theTau)
std::list< CompositeCandidate >::reverse_iterator compCandRevIter
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
math::XYZTLorentzVector LorentzVector
#define abs(x)
Definition: mlp_lapack.h:159
PFRecoTauDecayModeDeterminator(const edm::ParameterSet &iConfig)
const PFCandidateRefVector & signalPFChargedHadrCands() const
Charged hadrons in signal region.
Definition: PFTau.cc:75
std::list< CompositeCandidate > compCandList
const_iterator end() const
Termination of iteration.
Definition: RefVector.h:249
edm::RefProd< PFTauCollection > PFTauRefProd
references to PFTau collection
Definition: PFTauFwd.h:15
virtual size_type numberOfDaughters() const
number of daughters
edm::AssociationVector< PFTauRefProd, reco::PFTauDecayModeCollection > PFTauDecayModeAssociation
const_iterator begin() const
Initialize an iterator over the RefVector.
Definition: RefVector.h:244
U second(std::pair< T, U > const &p)
int iEvent
Definition: GenABIO.cc:243
OrphanHandle< PROD > put(std::auto_ptr< PROD > product)
Put a new product.
Definition: Event.h:85
tuple result
Definition: query.py:137
TauTagTools::sortByAscendingPt< CompositeCandidate > candAscendingSorter
bool first
Definition: L1TdeRCT.cc:94
bool getByLabel(InputTag const &tag, Handle< PROD > &result) const
Definition: Event.h:356
TauTagTools::sortByDescendingPt< CompositeCandidate > candDescendingSorter
void addDaughter(const Candidate &, const std::string &s="")
add a clone of the passed candidate as daughter
PFCandCommonVertexFitterBase * vertexFitter_
const PFCandidateRefVector & signalPFGammaCands() const
Gamma candidates in signal region.
Definition: PFTau.cc:79
const T & get() const
Definition: EventSetup.h:55
T const * product() const
Definition: ESHandle.h:62
virtual const Candidate * daughter(size_type) const
return daughter at a given position, i = 0, ... numberOfDaughters() - 1 (read only mode) ...
void set(const MagneticField *bField)
edm::RefToBase< Candidate > CandidateBaseRef
persistent reference to an object in a collection of Candidate objects
Definition: CandidateFwd.h:31
static bool gammaMatchSorter(const gammaMatchContainer &first, const gammaMatchContainer &second)
size_type size() const
Size of the RefVector.
Definition: RefVector.h:89
void set(reco::Candidate &c) const
set up a candidate
virtual void setMass(double m)
set particle mass
void mergePiZeroes(compCandList &, compCandRevIter)
virtual const LorentzVector & p4() const
four-momentum Lorentz vector
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Particle.h:25
virtual void produce(edm::Event &, const edm::EventSetup &)
virtual void setMass(double m)=0
set particle mass
math::PtEtaPhiELorentzVectorF LorentzVector
virtual const LorentzVector & p4() const =0
four-momentum Lorentz vector