CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
CATopJetAlgorithm.cc
Go to the documentation of this file.
1 // Original author: Brock Tweedie (JHU)
2 // Ported to CMSSW by: Sal Rappoccio (JHU)
3 
11 
12 using namespace std;
13 using namespace reco;
14 using namespace edm;
15 
16 // Run the algorithm
17 // ------------------
18 void CATopJetAlgorithm::run(const vector<fastjet::PseudoJet>& cell_particles,
19  vector<fastjet::PseudoJet>& hardjetsOutput,
20  std::shared_ptr<fastjet::ClusterSequence>& fjClusterSeq) {
21  if (verbose_)
22  cout << "Welcome to CATopSubJetAlgorithm::run" << endl;
23 
24  // Sum Et of the event
25  double sumEt = 0.;
26 
27  //make a list of input objects ordered by ET and calculate sum et
28  // list of fastjet pseudojet constituents
29  for (unsigned i = 0; i < cell_particles.size(); ++i) {
30  sumEt += cell_particles[i].perp();
31  }
32 
33  // Determine which bin we are in for et clustering
34  int sumEtBinId = -1;
35  for (unsigned int i = 0; i < sumEtBins_.size(); ++i) {
36  if (sumEt > sumEtBins_[i])
37  sumEtBinId = i;
38  }
39  if (verbose_)
40  cout << "Using sumEt = " << sumEt << ", bin = " << sumEtBinId << endl;
41 
42  // If the sum et is too low, exit
43  if (sumEtBinId < 0) {
44  return;
45  }
46 
47  // empty 4-vector
48  fastjet::PseudoJet blankJetA(0, 0, 0, 0);
49  blankJetA.set_user_index(-1);
50  const fastjet::PseudoJet blankJet = blankJetA;
51 
52  // Define adjacency variables which depend on which sumEtBin we are in
53  double deltarcut = deltarBins_[sumEtBinId];
54  double nCellMin = nCellBins_[sumEtBinId];
55 
56  if (verbose_)
57  cout << "useAdjacency_ = " << useAdjacency_ << endl;
58  if (verbose_ && useAdjacency_ == 0)
59  cout << "No Adjacency" << endl;
60  if (verbose_ && useAdjacency_ == 1)
61  cout << "using deltar adjacency" << endl;
62  if (verbose_ && useAdjacency_ == 2)
63  cout << "using modified adjacency" << endl;
64  if (verbose_ && useAdjacency_ == 3)
65  cout << "using calorimeter nearest neighbor based adjacency" << endl;
66  if (verbose_ && useAdjacency_ == 1)
67  cout << "Using deltarcut = " << deltarcut << endl;
68  if (verbose_ && useAdjacency_ == 3)
69  cout << "Using nCellMin = " << nCellMin << endl;
70 
71  if (verbose_)
72  cout << "About to do jet clustering in CA" << endl;
73  // run the jet clustering
74 
75  //cluster the jets with the jet definition jetDef:
76  // run algorithm
77  // std::shared_ptr<fastjet::ClusterSequence> fjClusterSeq;
78  // if ( !doAreaFastjet_ ) {
79  // fjClusterSeq = std::shared_ptr<fastjet::ClusterSequence>( new fastjet::ClusterSequence( cell_particles, jetDef ) );
80  // } else if (voronoiRfact_ <= 0) {
81  // fjClusterSeq = std::shared_ptr<fastjet::ClusterSequence>( new fastjet::ClusterSequenceArea( cell_particles, jetDef , *fjActiveArea_ ) );
82  // } else {
83  // fjClusterSeq = std::shared_ptr<fastjet::ClusterSequence>( new fastjet::ClusterSequenceVoronoiArea( cell_particles, jetDef , fastjet::VoronoiAreaSpec(voronoiRfact_) ) );
84  // }
85 
86  if (verbose_)
87  cout << "Getting inclusive jets" << endl;
88  // Get the transient inclusive jets
89  vector<fastjet::PseudoJet> inclusiveJets = fjClusterSeq->inclusive_jets(ptMin_);
90 
91  if (verbose_)
92  cout << "Getting central jets" << endl;
93  // Find the transient central jets
94  vector<fastjet::PseudoJet> centralJets;
95  for (unsigned int i = 0; i < inclusiveJets.size(); i++) {
96  if (inclusiveJets[i].perp() > ptMin_ && fabs(inclusiveJets[i].rapidity()) < centralEtaCut_) {
97  centralJets.push_back(inclusiveJets[i]);
98  }
99  }
100  // Sort the transient central jets in Et
101  sort(centralJets.begin(), centralJets.end(), greaterByEtPseudoJet);
102 
103  // These will store the 4-vectors of each hard jet
104  vector<math::XYZTLorentzVector> p4_hardJets;
105 
106  // These will store the indices of each subjet that
107  // are present in each jet
108  vector<vector<int> > indices(centralJets.size());
109 
110  // Loop over central jets, attempt to find substructure
111  vector<fastjet::PseudoJet>::iterator jetIt = centralJets.begin(), centralJetsEnd = centralJets.end();
112  if (verbose_)
113  cout << "Loop over jets" << endl;
114  int i = 0;
115  for (; jetIt != centralJetsEnd; ++jetIt) {
116  if (verbose_)
117  cout << "\nJet " << i << endl;
118  i++;
119  fastjet::PseudoJet localJet = *jetIt;
120 
121  // Get the 4-vector for this jet
122  p4_hardJets.push_back(math::XYZTLorentzVector(localJet.px(), localJet.py(), localJet.pz(), localJet.e()));
123 
124  // jet decomposition. try to find 3 or 4 hard, well-localized subjets, characteristic of a boosted top.
125  if (verbose_)
126  cout << "local jet pt = " << localJet.perp() << endl;
127  if (verbose_)
128  cout << "deltap = " << ptFracBins_[sumEtBinId] << endl;
129 
130  double ptHard = ptFracBins_[sumEtBinId] * localJet.perp();
131  vector<fastjet::PseudoJet> leftoversAll;
132 
133  // stage 1: primary decomposition. look for when the jet declusters into two hard subjets
134  if (verbose_)
135  cout << "Doing decomposition 1" << endl;
136  fastjet::PseudoJet ja, jb;
137  vector<fastjet::PseudoJet> leftovers1;
138  bool hardBreak1 =
139  decomposeJet(localJet, *fjClusterSeq, cell_particles, ptHard, nCellMin, deltarcut, ja, jb, leftovers1);
140  leftoversAll.insert(leftoversAll.end(), leftovers1.begin(), leftovers1.end());
141 
142  // stage 2: secondary decomposition. look for when the hard subjets found above further decluster into two hard sub-subjets
143  //
144  // ja -> jaa+jab ?
145  if (verbose_)
146  cout << "Doing decomposition 2. ja->jaa+jab?" << endl;
147  fastjet::PseudoJet jaa, jab;
148  vector<fastjet::PseudoJet> leftovers2a;
149  bool hardBreak2a = false;
150  if (hardBreak1)
151  hardBreak2a = decomposeJet(ja, *fjClusterSeq, cell_particles, ptHard, nCellMin, deltarcut, jaa, jab, leftovers2a);
152  leftoversAll.insert(leftoversAll.end(), leftovers2a.begin(), leftovers2a.end());
153  // jb -> jba+jbb ?
154  if (verbose_)
155  cout << "Doing decomposition 2. ja->jba+jbb?" << endl;
156  fastjet::PseudoJet jba, jbb;
157  vector<fastjet::PseudoJet> leftovers2b;
158  bool hardBreak2b = false;
159  if (hardBreak1)
160  hardBreak2b = decomposeJet(jb, *fjClusterSeq, cell_particles, ptHard, nCellMin, deltarcut, jba, jbb, leftovers2b);
161  leftoversAll.insert(leftoversAll.end(), leftovers2b.begin(), leftovers2b.end());
162 
163  // NOTE: it might be good to consider some checks for whether these subjets can be further decomposed. e.g., the above procedure leaves
164  // open the possibility of "subjets" that actually consist of two or more distinct hard clusters. however, this kind of thing
165  // is a rarity for the simulations so far considered.
166 
167  // proceed if one or both of the above hard subjets successfully decomposed
168  if (verbose_)
169  cout << "Done with decomposition" << endl;
170 
171  if (verbose_)
172  cout << "hardBreak1 = " << hardBreak1 << endl;
173  if (verbose_)
174  cout << "hardBreak2a = " << hardBreak2a << endl;
175  if (verbose_)
176  cout << "hardBreak2b = " << hardBreak2b << endl;
177 
178  fastjet::PseudoJet hardA = blankJet, hardB = blankJet, hardC = blankJet, hardD = blankJet;
179  if (!hardBreak1) {
180  hardA = localJet;
181  hardB = blankJet;
182  hardC = blankJet;
183  hardD = blankJet;
184  if (verbose_)
185  cout << "Hardbreak failed. Save subjet1=localJet" << endl;
186  }
187  if (hardBreak1 && !hardBreak2a && !hardBreak2b) {
188  hardA = ja;
189  hardB = jb;
190  hardC = blankJet;
191  hardD = blankJet;
192  if (verbose_)
193  cout << "First decomposition succeeded, both second decompositions failed. Save subjet1=ja subjet2=jb" << endl;
194  }
195  if (hardBreak1 && hardBreak2a && !hardBreak2b) {
196  hardA = jaa;
197  hardB = jab;
198  hardC = jb;
199  hardD = blankJet;
200  if (verbose_)
201  cout << "First decomposition succeeded, ja split succesfully, jb did not split. Save subjet1=jaa subjet2=jab "
202  "subjet3=jb"
203  << endl;
204  }
205  if (hardBreak1 && !hardBreak2a && hardBreak2b) {
206  hardA = jba;
207  hardB = jbb;
208  hardC = ja;
209  hardD = blankJet;
210  if (verbose_)
211  cout << "First decomposition succeeded, jb split succesfully, ja did not split. Save subjet1=jba subjet2=jbb "
212  "subjet3=ja"
213  << endl;
214  }
215  if (hardBreak1 && hardBreak2a && hardBreak2b) {
216  hardA = jaa;
217  hardB = jab;
218  hardC = jba;
219  hardD = jbb;
220  if (verbose_)
221  cout << "First decomposition and both secondary decompositions succeeded. Save subjet1=jaa subjet2=jab "
222  "subjet3=jba subjet4=jbb"
223  << endl;
224  }
225 
226  // check if we are left with >= 3 hard subjets
227  fastjet::PseudoJet subjet1 = blankJet;
228  fastjet::PseudoJet subjet2 = blankJet;
229  fastjet::PseudoJet subjet3 = blankJet;
230  fastjet::PseudoJet subjet4 = blankJet;
231  subjet1 = hardA;
232  subjet2 = hardB;
233  subjet3 = hardC;
234  subjet4 = hardD;
235 
236  // record the hard subjets
237  vector<fastjet::PseudoJet> hardSubjets;
238 
239  if (verbose_) {
240  std::cout << "HardA : user_index = " << hardA.user_index() << ", (Pt,Y,Phi,M) = (" << hardA.pt() << ", "
241  << hardA.rapidity() << ", " << hardA.phi() << ", " << hardA.m() << ")" << std::endl;
242 
243  std::cout << "HardB : user_index = " << hardB.user_index() << ", (Pt,Y,Phi,M) = (" << hardB.pt() << ", "
244  << hardB.rapidity() << ", " << hardB.phi() << ", " << hardB.m() << ")" << std::endl;
245 
246  std::cout << "HardC : user_index = " << hardC.user_index() << ", (Pt,Y,Phi,M) = (" << hardC.pt() << ", "
247  << hardC.rapidity() << ", " << hardC.phi() << ", " << hardC.m() << ")" << std::endl;
248 
249  std::cout << "HardD : user_index = " << hardD.user_index() << ", (Pt,Y,Phi,M) = (" << hardD.pt() << ", "
250  << hardD.rapidity() << ", " << hardD.phi() << ", " << hardD.m() << ")" << std::endl;
251  }
252 
253  // Check to see if any subjects are counted amongst the "hard" subjets from previous
254  // lines. NOTE: In Fastjet 3.0, the default "user_index" changed from 0 to -1, so
255  // this can no longer be used as a designator for the veto of "blankJet" subjets,
256  // and now switch to pt > some small value.
257  if (subjet1.pt() > 0.0001)
258  hardSubjets.push_back(subjet1);
259  if (subjet2.pt() > 0.0001)
260  hardSubjets.push_back(subjet2);
261  if (subjet3.pt() > 0.0001)
262  hardSubjets.push_back(subjet3);
263  if (subjet4.pt() > 0.0001)
264  hardSubjets.push_back(subjet4);
265  sort(hardSubjets.begin(), hardSubjets.end(), greaterByEtPseudoJet);
266 
267  // Use new fastjet functionality to create a Pseudojet from constituents
268  fastjet::PseudoJet candidate = join(hardSubjets);
269  // Reset the jet's 4-vector to the "ungroomed" value
270  candidate.reset_momentum(jetIt->px(), jetIt->py(), jetIt->pz(), jetIt->e());
271 
272  if (verbose_) {
273  std::cout << "Final top-jet candidate: (Pt,Y,Phi,M) = (" << candidate.pt() << ", " << candidate.rapidity() << ", "
274  << candidate.phi() << ", " << candidate.m() << ")" << std::endl;
275  std::vector<fastjet::PseudoJet> pieces = candidate.pieces();
276  std::cout << "Number of pieces = " << pieces.size() << std::endl;
277  for (std::vector<fastjet::PseudoJet>::const_iterator ibegin = pieces.begin(), iend = pieces.end(), i = ibegin;
278  i != iend;
279  ++i) {
280  std::cout << " Piece : " << i - ibegin << ", (Pt,Y,Phi,M) = (" << i->pt() << ", " << i->rapidity() << ", "
281  << i->phi() << ", " << i->m() << ")" << std::endl;
282  }
283  }
284  // Add to the list
285  hardjetsOutput.push_back(candidate);
286  }
287 }
288 
289 //-----------------------------------------------------------------------
290 // determine whether two clusters (made of calorimeter towers) are living on "adjacent" cells. if they are, then
291 // we probably shouldn't consider them to be independent objects!
292 //
293 // From Sal: Ignoring genjet case
294 //
295 bool CATopJetAlgorithm::adjacentCells(const fastjet::PseudoJet& jet1,
296  const fastjet::PseudoJet& jet2,
297  const vector<fastjet::PseudoJet>& cell_particles,
298  const fastjet::ClusterSequence& theClusterSequence,
299  double nCellMin) const {
300  double eta1 = jet1.rapidity();
301  double phi1 = jet1.phi();
302  double eta2 = jet2.rapidity();
303  double phi2 = jet2.phi();
304 
305  double deta = abs(eta2 - eta1) / 0.087;
306  double dphi = fabs(reco::deltaPhi(phi2, phi1)) / 0.087;
307 
308  return ((deta + dphi) <= nCellMin);
309 }
310 
311 //-------------------------------------------------------------------------
312 // attempt to decompose a jet into "hard" subjets, where hardness is set by ptHard
313 //
314 bool CATopJetAlgorithm::decomposeJet(const fastjet::PseudoJet& theJet,
315  const fastjet::ClusterSequence& theClusterSequence,
316  const vector<fastjet::PseudoJet>& cell_particles,
317  double ptHard,
318  double nCellMin,
319  double deltarcut,
320  fastjet::PseudoJet& ja,
321  fastjet::PseudoJet& jb,
322  vector<fastjet::PseudoJet>& leftovers) const {
323  bool goodBreak;
324  fastjet::PseudoJet j = theJet;
325  double InputObjectPt = j.perp();
326  if (verbose_)
327  cout << "Input Object Pt = " << InputObjectPt << endl;
328  if (verbose_)
329  cout << "ptHard = " << ptHard << endl;
330  leftovers.clear();
331  if (verbose_)
332  cout << "start while loop" << endl;
333 
334  while (true) { // watch out for infinite loop!
335  goodBreak = theClusterSequence.has_parents(j, ja, jb);
336  if (!goodBreak) {
337  if (verbose_)
338  cout << "bad break. this is one cell. can't decluster anymore." << endl;
339  break; // this is one cell, can't decluster anymore
340  }
341 
342  if (verbose_)
343  cout << "good break. ja Pt = " << ja.perp() << " jb Pt = " << jb.perp() << endl;
344 
346 
347  // check if clusters are adjacent using a constant deltar adjacency.
348  double clusters_deltar = fabs(ja.eta() - jb.eta()) + fabs(deltaPhi(ja.phi(), jb.phi()));
349 
350  if (verbose_ && useAdjacency_ == 1)
351  cout << "clusters_deltar = " << clusters_deltar << endl;
352  if (verbose_ && useAdjacency_ == 1)
353  cout << "deltar cut = " << deltarcut << endl;
354 
355  if (useAdjacency_ == 1 && clusters_deltar < deltarcut) {
356  if (verbose_)
357  cout << "clusters too close. consant adj. break." << endl;
358  break;
359  }
360 
361  // Check if clusters are adjacent using a DeltaR adjacency which is a function of pT.
362  double clusters_deltaR = deltaR(ja.rapidity(), ja.phi(), jb.rapidity(), jb.phi());
363 
364  if (verbose_ && useAdjacency_ == 2)
365  cout << "clusters_deltaR = " << clusters_deltaR << endl;
366  if (verbose_ && useAdjacency_ == 2)
367  cout << "0.4-0.0004*InputObjectPt = " << 0.4 - 0.0004 * InputObjectPt << endl;
368 
369  if (useAdjacency_ == 2 && clusters_deltaR < 0.4 - 0.0004 * InputObjectPt) {
370  if (verbose_)
371  cout << "clusters too close. modified adj. break." << endl;
372  break;
373  }
374 
375  // Check if clusters are adjacent in the calorimeter.
376  if (useAdjacency_ == 3 && adjacentCells(ja, jb, cell_particles, theClusterSequence, nCellMin)) {
377  if (verbose_)
378  cout << "clusters too close in the calorimeter. calorimeter adj. break." << endl;
379  break; // the clusters are "adjacent" in the calorimeter => shouldn't have decomposed
380  }
381 
382  if (verbose_)
383  cout << "clusters pass distance cut" << endl;
384 
386 
387  if (verbose_)
388  cout << "ptHard = " << ptHard << endl;
389 
390  if (ja.perp() < ptHard && jb.perp() < ptHard) {
391  if (verbose_)
392  cout << "two soft clusters. dead end" << endl;
393  break; // broke into two soft clusters, dead end
394  }
395 
396  if (ja.perp() > ptHard && jb.perp() > ptHard) {
397  if (verbose_)
398  cout << "two hard clusters. done" << endl;
399  return true; // broke into two hard clusters, we're done!
400  }
401 
402  else if (ja.perp() > jb.perp()) { // broke into one hard and one soft, ditch the soft one and try again
403  if (verbose_)
404  cout << "ja hard jb soft. try to split hard. j = ja" << endl;
405  j = ja;
406  vector<fastjet::PseudoJet> particles = theClusterSequence.constituents(jb);
407  leftovers.insert(leftovers.end(), particles.begin(), particles.end());
408  } else {
409  if (verbose_)
410  cout << "ja hard jb soft. try to split hard. j = jb" << endl;
411  j = jb;
412  vector<fastjet::PseudoJet> particles = theClusterSequence.constituents(ja);
413  leftovers.insert(leftovers.end(), particles.begin(), particles.end());
414  }
415  }
416 
417  if (verbose_)
418  cout << "did not decluster." << endl; // did not decluster into hard subjets
419 
420  ja.reset(0, 0, 0, 0);
421  jb.reset(0, 0, 0, 0);
422  leftovers.clear();
423  return false;
424 }
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
tuple pieces
Definition: csv2json.py:32
bool greaterByEtPseudoJet(fastjet::PseudoJet const &j1, fastjet::PseudoJet const &j2)
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
ptMin_(conf.getParameter< double >("ptMin"))
bool adjacentCells(const fastjet::PseudoJet &jet1, const fastjet::PseudoJet &jet2, const std::vector< fastjet::PseudoJet > &cell_particles, const fastjet::ClusterSequence &theClusterSequence, double nCellMin) const
bool decomposeJet(const fastjet::PseudoJet &theJet, const fastjet::ClusterSequence &theClusterSequence, const std::vector< fastjet::PseudoJet > &cell_particles, double ptHard, double nCellMin, double deltarcut, fastjet::PseudoJet &ja, fastjet::PseudoJet &jb, std::vector< fastjet::PseudoJet > &leftovers) const
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
void run(const std::vector< fastjet::PseudoJet > &cell_particles, std::vector< fastjet::PseudoJet > &hardjetsOutput, std::shared_ptr< fastjet::ClusterSequence > &fjClusterSeq)
Find the ProtoJets from the collection of input Candidates.
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
T perp() const
Magnitude of transverse component.
tuple cout
Definition: gather_cfg.py:144
list indices
Definition: dqmdumpme.py:50